ChanServ changed the topic of #crystal-lang to: The Crystal programming language | http://crystal-lang.org | Crystal 0.34.0 | Fund Crystal's development: http://is.gd/X7PRtI | GH: https://github.com/crystal-lang/crystal | Docs: http://crystal-lang.org/docs/ | API: http://crystal-lang.org/api/ | Gitter: https://gitter.im/crystal-lang/crystal
Nekka has quit [Ping timeout: 246 seconds]
Nekka has joined #crystal-lang
<FromGitter> <watzon> I find that searching `language:crystal search-term` on github works really well. Hopefully crystalshards will support gitlab in the not too distant future too.
<straight-shoota> watzon, shardbox already does
<FromGitter> <watzon> Well it supports it, but shardbox requires manual insertion doesn't it? It doesn't index.
<straight-shoota> it doesn't care where a shard is hosted, as long as `shards install` can find it
<straight-shoota> For now it doesn't have full autodiscovery, yes.
<FromGitter> <watzon> Is that planned?
<FromGitter> <watzon> Also is it planned to make shardbox official? I saw a comment on a post in the Ruby subreddit yesterday that mentioned difficulty in finding a place where shards are listed because shardbox isn't linked to on the crystal-lang homepage. I made sure to tell them that that's because shardbox isn't official for now.
<straight-shoota> Technically, it's super simple. GitHub discovery is more or less already implemented, GitLab etc. should be fairly easy to do. I'm not sure it's a good idea though to list every single repository with a shard.yml
<straight-shoota> shardbox is linked on https://crystal-lang.org/community/
<straight-shoota> if that's your definition of official, the it is =)
<FromGitter> <watzon> I think there should be some requirement for indexing so you can explicitly make sure your project is indexed. Were it just github you could look for a topic `crystal-lang` or something, but it's not. It could be possible to have a section in `shard.yml` or something, or only check for projects that have releases.
<FromGitter> <watzon> Didn't know there was a link on the community page. I'll have to update my answer on reddit.
<straight-shoota> The requirement for making sure a project is indexed is simply adding it to https://github.com/shardbox/catalog
<straight-shoota> That can be done by the author or anyone else
<FromGitter> <Blacksmoke16> you can remove https://github.com/shardbox/catalog/blob/master/catalog/Logging_and_monitoring.yml#L12-L13, i archived it because of `Log` module being a thing now
<FromGitter> <watzon> Personally I'm not a fan of that approach. It requires a PR and it's just another thing to maintain on top of any projects you're working on. Like I moved my `tourmaline` project to the `protoncr` org a bit ago, but I haven't gone in and updated it yet.
<FromGitter> <watzon> Guess I better do that
<straight-shoota> The implementation of GitHub discovery is actually for a tool to make adding uncataloged shards from GutHub easy
<straight-shoota> Blacksmoke16 +1
<straight-shoota> watzon, I fully understand your concerns
<straight-shoota> But I don't think there's a better way to manage such a catalog than as a git repo
<straight-shoota> Having a simple tool for adding new shards to the catalog would certainly help the process
<FromGitter> <watzon> For sure. If shardbox is going to be the official tool it would be nice if shards would do that.
<FromGitter> <watzon> I just got Tourmaline updated in the catalog though
Nekka has quit [Ping timeout: 272 seconds]
<straight-shoota> Great
<straight-shoota> you only need to add description and mirrors once
<straight-shoota> not in every category
<straight-shoota> the formatter check will complain about that :D
<straight-shoota> just another example why it's not super user friendly^^
<FromGitter> <watzon> Ahh ok, I was just keeping more or less with what was there before
<FromGitter> <watzon> But yes haha
<FromGitter> <watzon> So I should just have `- github: protoncr/tourmaline` in one of the categories?
<FromGitter> <watzon> And then have everything in the other?
<straight-shoota> exactly
Nekka has joined #crystal-lang
<FromGitter> <watzon> I know that I know the answer to this, but it's been a long day and I'm spacing
<FromGitter> <watzon> What would be the best way to convert a string to binary representation?
<FromGitter> <Blacksmoke16> .to_s 2
<FromGitter> <watzon> That's for integers haha
<FromGitter> <3n-k1> loop through each character of the string and bitshift to get the representation of each bit? i'm not sure of any other way to do it
<FromGitter> <3n-k1> that doesn't sound like fun with unicode though
<FromGitter> <watzon> I guess I just have to use `IO::ByteFormat::LittleEndian.decode` on each byte and then convert that to a binary string
<FromGitter> <watzon> Thought I remembered there being an easier way, but I guess not
<FromGitter> <Blacksmoke16> :thinking:
<FromGitter> <Blacksmoke16> does it have to be binary, or just the bytes?
<FromGitter> <watzon> I want the binary representation, the bytes are easy
<FromGitter> <Blacksmoke16> what about hex? :P
<FromGitter> <watzon> This is my idea right now ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5eb3658322f9c45c2a743b7e]
<FromGitter> <Blacksmoke16> oo
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/90so
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <watzon> Hmm interesting. Cold probably have some performance penalties for larger strings as compared to using IO::ByteFormat, couldn't it?
<FromGitter> <Blacksmoke16> no idea
<FromGitter> <Blacksmoke16> `str.to_slice.hexstring.to_u64(16).to_s 2 ⏎ `
<FromGitter> <Blacksmoke16> could work too
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <watzon> Only if the string fits into a u64 though.
<FromGitter> <3n-k1> i write too much c https://carc.in/#/r/90su
<FromGitter> <Blacksmoke16> true, i suppose it would prob be easy to get over that if you use a large enough string
<FromGitter> <watzon> Well that's certainly a way to do it haha
<FromGitter> <watzon> Probably the most efficient, though definitely not the most pretty
<FromGitter> <3n-k1> i've had c pounded into me and now i just see strings as integer arrays lmao
deavmi has quit [Ping timeout: 272 seconds]
deavmi has joined #crystal-lang
<FromGitter> <watzon> 76/4
straight-shoota has quit [Ping timeout: 246 seconds]
rocx has left #crystal-lang ["👏 developers 👏 developers 👏 developers 👏 developers 👏 developers"]
return0e_ has joined #crystal-lang
return0e has quit [Ping timeout: 256 seconds]
rocx has joined #crystal-lang
rocx has quit [Ping timeout: 260 seconds]
_ht has joined #crystal-lang
zorp has joined #crystal-lang
Nekka has quit [Ping timeout: 260 seconds]
Nekka has joined #crystal-lang
wakatara has joined #crystal-lang
_ht has quit [Remote host closed the connection]
_ht has joined #crystal-lang
return0e has joined #crystal-lang
return0e_ has quit [Read error: Connection reset by peer]
<FromGitter> <neutrinog> why can't I do this? ⏎ ⏎ ```class MyClass(T) ⏎ @@stuff = Hash(String, T).new ⏎ end``` ⏎ ⏎ I get a compile error `can't infer the type parameter T for the generic class MyClass(T). Please provide it explicitly ... [https://gitter.im/crystal-lang/crystal?at=5eb3a6e59f0c955d7dac376d]
<oprypin> jhass: can i pretty please get a plaintext field to put code in on carc.in? i quite literally can't use it on mobile https://i.imgur.com/zc8EiNw.jpg
sz0 has quit [Quit: Connection closed for inactivity]
<oprypin> neutrinog, i guess the `initialize` needs to refer to the T in some way
<oprypin> ah lol this is a class variable. never thought of that use case. well yeah, this is just one global variable same for all instances, there's no feature to create them on the fly somehow per instantiation of a generic
<FromGitter> <neutrinog> yeah I was playing around with generic singletons.
<FromGitter> <neutrinog> I guess it's not possible.
<oprypin> maybe it should be. c# does it apparently
<FromGitter> <neutrinog> I'm trying to get around the fact that class variables are not the same for subclases. It might be hard to explain without an example, but basically you can get around that by using a class variable that itself is a singleton.
<FromGitter> <neutrinog> But then you have to create a bunch of singletons. Hence my attempt at a generic singleton.
wakatara has left #crystal-lang ["Using Circe, the loveliest of all IRC clients"]
<oprypin> neutrinog, wow i'm actually completely blanking on how to achieve this
<oprypin> aaaa why does it seem impossible
<oprypin> only found a different way to break it https://carc.in/#/r/90tn
<FromGitter> <neutrinog> Is there a way we can request this feature?
<oprypin> hehe even this is no good https://carc.in/#/r/90tz
<oprypin> @neutrinog, yea just an issue in github. just make a good case for it, describe it *generically*
<FromGitter> <neutrinog> yeah I'm looking into that now. Making sure no one else has a similar issue open.
<oprypin> neutrinog, ok this is the simplest way i can think of 👌 https://carc.in/#/r/90u2
<FromGitter> <neutrinog> ah brilliant!
<oprypin> that's not what i'd call it 😂 anyway i'd like to share my code findings once you create the issue
<FromGitter> <neutrinog> yeah, it would be nice to have some syntax that's a little less... obtuse :)
<FromGitter> <neutrinog> this might be the same issue https://github.com/crystal-lang/crystal/issues/8861
<oprypin> mm very much related
<oprypin> but i think it's not convincingly written
<oprypin> my example is pretty bad though. .hash is an actual hash, there's no guarantee that it's unique
<oprypin> why doesn't Class have a typeid method
<jhass> oprypin: pull requests welcome :) You can also write an app for it, as long as it shares carc.in links I'm fine :D
<jhass> I was about to suggest curl but then I read mobile
<oprypin> hey i have Termux but eeehhhh
sz0 has joined #crystal-lang
<jhass> maybe it's as easy as putting the right CSS or options to codemirror for that one though
<jhass> can't imagine nobody got codemirror to properly render on mobile yet
<oprypin> yea
<jhass> for your code above, let's hope nobody ever puts a value type into it :P
<jhass> maybe there's a solution using macro inherited but for that you'd need to know more about the actual usecase I guess
<oprypin> oh dang, macro inherited
<oprypin> jhass: wait, wasn't i already putting value types into it?
<jhass> well, just an Int32 which is SizeT?
<jhass> oh Float32 but same
<jhass> PtrT? I always forget what's the pointer width type
<oprypin> jhass: i think you're looking at the old example
<jhass> https://carc.in/#/r/90u2 isn't the latest?
<oprypin> it is
<jhass> ah I misread, didn't notice the nested hash
<oprypin> how to get typeid properly though? is .crystal_type_id intentionally hidden?
<oprypin> jhass: i think macro inherited doesn't run for instantiating a generic
<jhass> yeah not saying it's an as generic solution
<jhass> But from what I read above the generic class is only in play for the subclasses, so Base(T); A < Base(A); B < Base(B) etc
<oprypin> are u reading the issue?
<oprypin> cuz i think this is deferent
<oprypin> different*
<jhass> I'm reading the chat history.
<jhass> and feels very very XYy
<jhass> I'm saying macro inherited may pose a better solution to the underlying problem that's being tried to solve
<jhass> not to the approach chosen trying to solve it
<jhass> but can't say for sure knowing so little about the underlying problem
<FromGitter> <neutrinog> I added a comment to that issue. https://github.com/crystal-lang/crystal/issues/8861#issuecomment-625080632
<FromGitter> <neutrinog> if it's unclear let me know so I can update it.
<yxhuvud> jhass: hrrm. I may have to update my highlighting settings.
<oprypin> neutrinog: yea that one has a ton of different solutions
<jhass> yxhuvud: you have one yx? :D
<FromGitter> <neutrinog> So did I read right you guys don't think the solution you created here https://carc.in/#/r/90u2 will work correctly?
<FromGitter> <neutrinog> it seems like it does
<oprypin> i don't like the .hash. also it's probably slower than you'd like
<jhass> it probably will, but it's also... kinda not nice :)
<oprypin> does .crystal_type_id instead of .hash work?
<FromGitter> <neutrinog> yeah I'm building a game engine. Performance is kinda important.
<oprypin> yes .crystal_type_id is strictly better than .hash then
<yxhuvud> jhass: something like that yes. :)
<oprypin> @neutrinog: for your use case i think you can just do macro make_reference_pool(t) and put the whole class body into it
<jhass> not sure I quite got the usecase quite right, but maybe just something like this? https://carc.in/#/r/90u6
<oprypin> and pre- instantiate them all
<FromGitter> <neutrinog> jhass: Counter has to be a singleton otherwise sub-classing Entity will create different counters.
<jhass> well you can just shadow the subclassed variable with macro inherited
<FromGitter> <neutrinog> Not sure what all that means. Can you elaborate?
<jhass> still not sure I quite got your requirements tbh.
<FromGitter> <neutrinog> ah ok. So the inherited macro is called on the subclass
<jhass> yeah
<oprypin> neutrinog, https://carc.in/#/r/90ud
<oprypin> also... have you considered, like, relying on actual garbage collection
<FromGitter> <neutrinog> I am actually. All I'm doing for the garbage collection is removing items from a hash once all their references are gone. Then I rely on `finally` to do the clean up.
<oprypin> but you dont need to remove anything
<FromGitter> <neutrinog> The important part I'm implementing is the reference counter so I can avoid loading resource more than once.
<oprypin> once all references are gone, it *is* garbage collected
<oprypin> maybe u just need https://crystal-lang.org/api/WeakRef.html
<FromGitter> <neutrinog> oh interesting.
Mikaela has quit [Quit: Mikaela]
Mikaela has joined #crystal-lang
flips has quit [*.net *.split]
beepdog has quit [*.net *.split]
twistedpixels has quit [*.net *.split]
flips has joined #crystal-lang
twistedpixels has joined #crystal-lang
beepdog has joined #crystal-lang
<FromGitter> <neutrinog> One potential problem here, I'm not sure how much of a problem it will be in my case. If I have a hash of weak references, my hash will simply grow
<oprypin> @neutrinog: yes hmm
<oprypin> there should be a weakrefhash
<oprypin> python has one
<oprypin> the implementation is fascinating
<oprypin> looks like it stores weakrefs to proxies which on finalization mark the items to be deleted in the dictionary
<oprypin> and all methods first execute pending removals
<FromGitter> <Whaxion> Hello, I'm trying to set an Array(Model) with Array(User) (User < Model) but I can't do it, I've seen this article https://crystal-lang.org/reference/syntax_and_semantics/inheritance.html#covariance-and-contravariance but instead of changing my Array(User) is it possible to somehow cast it to Array(Model) ? 😃
<oprypin> .map &.as(Model)
<oprypin> or populate that array with User.new.as(Model) in the first place
<FromGitter> <neutrinog> I'm not sure I want to search through the dictionary every time a method is called.
<FromGitter> <Whaxion> Thanks @oprypin it works perfectly 😄
<FromGitter> <neutrinog> @oprypin here's my final pool implementation with weak references. https://carc.in/#/r/90uy
<oprypin> @neutrinog: mmmmm that's iterating over everything on every address
<oprypin> access*
<FromGitter> <neutrinog> yeah that's the python code was doing as well. At least that was my understanding. It's been awhile since I had to write python.
<oprypin> no no it's not
<oprypin> it iterates over a list that only has items marked to be deleted
<oprypin> tbh at this point i think your idea with reference counting is easier
<FromGitter> <neutrinog> yeah I'll stick with that for now. No looping required. And I guess I'm stuck with writing some boiler plate singletons for now until we get generic class variables (if we get them)
<FromGitter> <neutrinog> ah.. but I forgot about the macros again. I can probably create a reasonably clean solution now.
_ht has quit [Remote host closed the connection]
_ht has joined #crystal-lang
hightower2 has joined #crystal-lang
ryanprior has quit [Quit: killed]
beepdog has quit [Quit: killed]
olbat[m] has quit [Quit: killed]
ryanprior has joined #crystal-lang
<oprypin> neutrinog: yes the macro https://carc.in/#/r/90ud
olbat[m] has joined #crystal-lang
beepdog has joined #crystal-lang
<oprypin> neutrinog: i just realized, this is just doing generics the Go way. can't be bad, right?
<oprypin> 😩😂
straight-shoota has joined #crystal-lang
<FromGitter> <waghanza> hi, is this ok to build an app on *alpine* (with `musl`), but to run it on *linux* (with `glibc`) ?
<raz> if it's a static build then i would say yes
<raz> (i think that's what alpine/musl is commonly used for - build static binary, deploy anywhere)
rocx has joined #crystal-lang
<straight-shoota> Yes, that's the purpose of static linking. You don't need to care what libraries are available in the runtime system, everything is included in the executable
<FromGitter> <waghanza> ok, ❤️
<FromGitter> <Afront> Can I use Process.run inside a spawn block? I tried it and it soft crashes after it tries running the process.
<straight-shoota> Afront, yes that should work without issues
<straight-shoota> can you share your code?
<straight-shoota> A common reason for unexpected failure is that the main fiber exits.
<jhass> I see straight-shoota got converted to IRC :D
<straight-shoota> Then the program will exit and stop all spawend fibers
<straight-shoota> haha, I'm trying
<FromGitter> <Afront> Oh thanks @straight-shoota, that was the problem. I didn't put sleep after `yield`ing the main fiber.
<FromGitter> <Afront> It works now, thanks!
<jhass> why don't you run the process in the main fiber if it has nothing else to do?
<FromGitter> <hugopl> Is this a language limitation or a bug? ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5eb40942adb0ec5c2bee252c]
<FromGitter> <Blacksmoke16> try `puts call(->{ @value.upcase })`
<FromGitter> <hugopl> but why the syntax sugar doesn't work?
<FromGitter> <hugopl> is there a reason?
<FromGitter> <Blacksmoke16> parser prob just not taking the `@` into account, maybe search github and see if theres an issue for it already
<FromGitter> <hugopl> yeah, I was looking for that just now, and found none
<FromGitter> <hugopl> I'm going to search a bit more... then create the issue if I find none
<FromGitter> <Blacksmoke16> 👍
<FromGitter> <neutrinog> hey, I created a macro. It's in one file, and I'm using it in another. I've imported the macro file but I'm getting an error `Error: macro 'your_macro_name' must be defined before this point but is defined later`
<FromGitter> <neutrinog> any ideas?
<FromGitter> <Blacksmoke16> make sure you require it before you use it?
<FromGitter> <neutrinog> yep. Imported at the top of the file.
<FromGitter> <Blacksmoke16> not using it anywhere else?
<FromGitter> <neutrinog> in the specs
<FromGitter> <neutrinog> hm.. deleted the specs temporarily and got this error. `undefined method...`
<FromGitter> <Blacksmoke16> :thinking: hard to say without seeing the code
<FromGitter> <Blacksmoke16> pretty sure it has to be some require order issue tho
<FromGitter> <neutrinog> yeah. it's a big project..hmm.
<FromGitter> <neutrinog> ok maybe this is not ideal but here's a screenshot.
<FromGitter> <neutrinog> The two files are open on the right, the error is below. You can see the relative folder location on the left.
<FromGitter> <Blacksmoke16> maybe try adding `--error-trace` and see if that adds anything useful
<FromGitter> <neutrinog> hmm.. not much. I'm running `crystal spec`. So I see call tree and it fails when importing the core library. it's standard for the root file in a library to simply call `require "./mylib/*"` right?
<FromGitter> <Blacksmoke16> ehh i usually run into require issues when doing that
<FromGitter> <Blacksmoke16> its afaik its required in ABC order, so if the macro was defined in a `m` file, but used in an `b` file, then you have to manually require `m` within `b`
<FromGitter> <neutrinog> sure, but the manual import does not seem to work.
dostoyevsky has quit [Quit: leaving]
dostoyevsky has joined #crystal-lang
<FromGitter> <neutrinog> hm... so if I use `extend self` in the module in my macro file I properly access the macro without problems using it like a method of the module.
<FromGitter> <neutrinog> I think the error message may be misleading because it can clearly find the import.
<FromGitter> <neutrinog> I don't even need the manual import now.
<FromGitter> <Blacksmoke16> nice
postmodern has quit [Quit: Leaving]
<FromGitter> <neutrinog> oh.. so I don't need to extend the module at all. This is so strange. The two files have the same namespace so it doesn't make sense why i need to specify when calling the macro.
<FromGitter> <neutrinog> ok so this is my solution. The macro generates a particular class so I nested it inside there so I can simply call it like `ReferencePool.create_persistent_pool(Texture)`. This seems to work in all cases. I still don't understand why it didn't initially work, but at least this solution doesn't look hacky.
<oprypin> @neutrinog: if you have even one asterisk inside a require in your project, all bets are off
<FromGitter> <neutrinog> lol. So what do you suggestion? Just manually importing everything. I'm too lazy. :P
<FromGitter> <neutrinog> But seriously, what's the standard?
<FromGitter> <Blacksmoke16> or at least have file that requires related files, then you main file just requires all those specific "index" files?
<FromGitter> <j8r> IMO `require "**"` is bad design decision
<FromGitter> <j8r> double wildcards in requires
<FromGitter> <j8r> simple wildcard is easy enough
<FromGitter> <neutrinog> ok so maybe at most use a single wildcard at the top of the lib and then next things below in folders. Following suit as needed.
<oprypin> @neutrinog: yes that's how everyone else does it in every other programming language
<FromGitter> <j8r> using double leads to unwanting
<FromGitter> <j8r> ... effects
<oprypin> expect Ruby but. ..
<FromGitter> <j8r> @neutrinog yep, require only what is needed
<oprypin> single is also unpredictable
<FromGitter> <j8r> yep oprypin, but better
<FromGitter> <j8r> sometimes not that much, if there are only few files
<FromGitter> <Blacksmoke16> i only use `*` when its a dir that are just implementations of the same interface/or all realted
<FromGitter> <Blacksmoke16> like `require "./events/*"` where that is like `AbstractEvent`, `SomeEvent`, `AnotherEvent` etrc
<FromGitter> <neutrinog> ok, for some reason I thought `crystal init` generated the root file with the double wildcards. So I thought that was the standard, however the last time I init'd a project was 2 years ago.
<oprypin> oh could very well be
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5eb41b0e0b23797ec06a7172]
<FromGitter> <Blacksmoke16> doesnt have any requires, just one file under `src`
<oprypin> yes
<FromGitter> <neutrinog> yeah that's definitely different from how I remember it. ug... my fault.
<FromGitter> <neutrinog> time to update all my imports (or the lack thereof)
renich has joined #crystal-lang
<jhass> Ruby does not support wildcard requires. Some people do Dir["**.rb"].each(&:require) but it's generally frowned upon for exactly the reasons
<jhass> I agree that wildcard require was a bad idea
<FromGitter> <lodenos> Hello Guy's
<oprypin> what, ruby doesnt support wildcards at all??
<FromGitter> <Blacksmoke16> o/
<oprypin> wow
<FromGitter> <lodenos> One thing it's so weird comportment for my ⏎ This code ⏎ ⏎ ```code paste, see link``` ⏎ ... [https://gitter.im/crystal-lang/crystal?at=5eb41e7aadb0ec5c2bee6b95]
<jhass> oprypin: no, it has this though https://ruby-doc.com/core/Module.html#method-i-autoload
<oprypin> uhhh what
<oprypin> is this based on converting it to lowercase for the file name
<jhass> pretty much, UpperCamelCase to lower_underscore_case
Human_G33k has joined #crystal-lang
HumanGeek has quit [Ping timeout: 272 seconds]
return0e_ has joined #crystal-lang
renich has quit [Ping timeout: 264 seconds]
return0e has quit [Ping timeout: 264 seconds]
beepdog has quit [Quit: Idle for 30+ days]
<raz> i think wildcard is nice to have. there's few cases where it's useful (due to the non-guaranteed import order), but it's in these cases it's a nice convenience (and imho clearer at a glance than the ruby contraption)
<FromGitter> <UnsolvedCypher_gitlab> For using the Crystal VSCode extension, do most people here use scry or just the default language server?
<FromGitter> <watzon> I don't bother with scry most of the time
<FromGitter> <watzon> Doesn't work very well as is
<FromGitter> <UnsolvedCypher_gitlab> Alright, it looks like the built-in autocompletion works well enough anyways. Thanks @watzon!
<FromGitter> <neutrinog> is it possible to pass a captured block to a macro?
<FromGitter> <neutrinog> e.g. `my_macro("arg") do {...}`
<FromGitter> <watzon> Macros can have a block if that's what you mean
<FromGitter> <neutrinog> I mean what's the syntax for accepting a callback to a macro.
<FromGitter> <neutrinog> I'm trying to generate a method that accepts a callback, but I want to define the callback when I call the macro.
<FromGitter> <watzon> Same as with a normal method I believe
<FromGitter> <Blacksmoke16> `{{yield}}`
<FromGitter> <watzon> ```macro my_macro(arg, &block) ⏎ yield ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5eb436cf7975db7ebfee25f4]
<FromGitter> <neutrinog> I'm trying to generate this with my macro ⏎ ⏎ ```some_method(arg, &callback)``` [https://gitter.im/crystal-lang/crystal?at=5eb437d7d898fe7a37708b68]
<FromGitter> <Blacksmoke16> `some_method(arg, {{block}})`?
<FromGitter> <Blacksmoke16> a playground link would prob be easier
<FromGitter> <watzon> Ok that's weird https://carc.in/#/r/90xt
<FromGitter> <watzon> Not what I expected haha
<FromGitter> <watzon> https://carc.in/#/r/90xv
<FromGitter> <watzon> There we go
<FromGitter> <neutrinog> ah ok. So similar question.
<FromGitter> <neutrinog> Can I do the same with initializing a class?
<FromGitter> <watzon> How do you mean?
<FromGitter> <neutrinog> can you do `def initialize(arg, &proc)`?
<FromGitter> <watzon> Sure
<FromGitter> <watzon> `initialize` can take a block
<FromGitter> <neutrinog> oops I had a typo in my code.
<FromGitter> <neutrinog> there seems to be a discrepancy between the local crystal playground (`crystal play`) and carc.in.
<FromGitter> <watzon> Well they're different software
<FromGitter> <watzon> What's the discrepancy?
<FromGitter> <neutrinog> This code here doesn't show the macro output locally https://carc.in/#/r/90xw
<FromGitter> <watzon> By "the macro output" you mean the compiled code from the macro?
<FromGitter> <watzon> https://carc.in/#/r/90xx
<FromGitter> <neutrinog> yes. Locally I only get ⏎ ⏎ ```sending regular to block ⏎ received regular ⏎ sending macro to block``` [https://gitter.im/crystal-lang/crystal?at=5eb43d6c97338850a2f2edb3]
<FromGitter> <neutrinog> but it's missing the last `received macro`
<FromGitter> <watzon> Macros can include a `{% debug %}` which shows the generated code
<FromGitter> <watzon> This ⏎ ⏎ ```call_class("macro") do |args| ⏎ puts "received #{args}" ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5eb43dc09f0c955d7dae0782]
<FromGitter> <neutrinog> I just mean prototyping with the local playground is misleading if it's not giving you the proper textual output on the side.
<FromGitter> <watzon> Idk what you mean
<FromGitter> <neutrinog> I was confused for awhile why my code wasn't working when in fact it was. The playground just wasn't logging all of the print statements.
<FromGitter> <watzon> Well it's logging the ones that are actually being called
<FromGitter> <neutrinog> not trying to belabor the point. It's not the end of the world. but you can see the difference in output here
<FromGitter> <watzon> It's the same output, just in a different format
<FromGitter> <watzon> You just have to click on the `(2 times) : String` to see the output of the print statement
<FromGitter> <neutrinog> it's missing the second call to "received.." onthe left
<hightower2> Hey if I have Array(String | Nil) and call compact! on it, shouldn't it change it's type to Array(String)?
<FromGitter> <watzon> Ahh I see what you're saying
<FromGitter> <Blacksmoke16> no
<FromGitter> <watzon> `crystal play` is not great
<FromGitter> <Blacksmoke16> because the type of the array is still `Array(String?)` it just doesn't have any `nil` values in it anymore
<FromGitter> <Blacksmoke16> would need to use `compact` to create a new array w/o `Nil` type included
<hightower2> oo, good one, thanks
<travis-ci> crystal-lang/crystal#d27f524 (master - Support `TypeNode.name(generic_args: false)` for generic instances (#9224)): The build passed. https://travis-ci.org/crystal-lang/crystal/builds/684351357
travis-ci has left #crystal-lang [#crystal-lang]
travis-ci has joined #crystal-lang
<DeBot> https://github.com/crystal-lang/crystal/pull/9224 (Support `TypeNode.name(generic_args: false)` for generic instances)
<hightower2> Hey are there any existing shards that can parse time spec like "2 days", "100 mins" etc?
<hightower2> (basically that just change this into Time::Span)
<repo> i noticed that crake isn't maintained for 4 years. are there alternatives?
<repo> i'm looking for something very similar
<FromGitter> <Blacksmoke16> prob just use option_parser and point each thing to method?
<FromGitter> <Blacksmoke16> `./bin/cli --some_task`
<repo> yeah but i want to have file tasks
<repo> similar to make
<FromGitter> <Blacksmoke16> `crystal ./tasks/task.cr`?
<FromGitter> <watzon> hightower2: https://crystalshards.org/shards/github/alexherbo2/chronic might work
<FromGitter> <watzon> Though it looks like it's just a cli
<FromGitter> <Blacksmoke16> that `ms` shard that one guy made can do it https://github.com/krthr/ms.cr#examples
<FromGitter> <Blacksmoke16> but you get milliseconds
<hightower2> mm both are very interesting, thanks!
<raz> repo: use Make
<raz> until someone invents one that solves more problems than it creates
<raz> every knows make and hates it equally. the alternatives fail on the 1st part and so people hate them even more.
<travis-ci> crystal-lang/crystal#f22ab9f (master - Force linking of `pthread_once` when compiling static binaries in musl (#9238)): The build passed. https://travis-ci.org/crystal-lang/crystal/builds/684366716
travis-ci has left #crystal-lang [#crystal-lang]
travis-ci has joined #crystal-lang
<DeBot> https://github.com/crystal-lang/crystal/pull/9238 (Fix segfaults when static linking with musl)
travis-ci has joined #crystal-lang
travis-ci has left #crystal-lang [#crystal-lang]
<travis-ci> crystal-lang/crystal#9efe317 (master - Refactor via private Path#empty? (#9137)): The build passed. https://travis-ci.org/crystal-lang/crystal/builds/684369342
return0e_ has quit [Read error: Connection reset by peer]
return0e has joined #crystal-lang
<FromGitter> <didactic-drunk> @repo sam (https://github.com/imdrasil/sam.cr) is a Rake-like task manager that's actively maintained.
<hightower2> thankfully also the docs for sam became better lately
hightower2 has quit [Ping timeout: 260 seconds]
hightower2 has joined #crystal-lang
sagax has quit [Ping timeout: 260 seconds]
<FromGitter> <watzon> There's no way to pause a fiber is there?
<FromGitter> <watzon> Seems like they have the ability to resume, but not pause
zorp has quit [Ping timeout: 256 seconds]
<FromGitter> <bew> Pause, by the fiber? Or from another fiber? Until resume? Or to let other fiber run in the mean time?
<FromGitter> <watzon> Pause from another fiber. I know I'm thinking about this the wrong way, but I'm trying to find out how to do what Ruby's `Thread` can do.
Sharcho has joined #crystal-lang
<Sharcho> Is there a build time option to disable multithreading?
<FromGitter> <Blacksmoke16> it's disabled by default so no option needed
<FromGitter> <Blacksmoke16> its opt in not opt out
<Sharcho> When I do ps on a crystal process, it shows 8 threads
<Sharcho> ps -e -T | grep mycrystalapp
<FromGitter> <Blacksmoke16> mmm
<FromGitter> <Blacksmoke16> whats the process? just like `puts "hello world"`?
<Sharcho> more or less, with a sleep in it
<FromGitter> <Blacksmoke16> could be internal stuff, a bit outside of my area of expertise tho
<FromGitter> <Blacksmoke16> like the event loop and such
<Sharcho> It happens with a program that contains only "sleep 1000", and crystal build --release
lanodan has quit [Ping timeout: 265 seconds]
<hightower2> Hey quick one about crecto, after i Repo.insert(obj), how do I get obj.id to actually be populated with the assigned DB id?
<FromGitter> <Blacksmoke16> :shrug: i thought that repo was abandoned
<hightower2> in favor of Repo::Query or?
_ht has quit [Remote host closed the connection]
<hightower2> actually no, query is query... looking at official docs there's no note of not using Repo
<FromGitter> <Blacksmoke16> no i mean the library itself. Last i heard it was no longer maintained
<FromGitter> <Blacksmoke16> guess its back now
<hightower2> interesting, I used it after someone praised its completeness here week or two ago, and the last commit is from a day or two ago
<FromGitter> <watzon> I'd recommend clear or granite personally
<hightower2> after completing a basic model with it, I am not too happy, would have used something else probably, but wel...
<FromGitter> <watzon> As an ORM
<FromGitter> <Blacksmoke16> hows your ORM going? :p
<FromGitter> <watzon> Paused for now. My brain needed a break haha
<FromGitter> <Blacksmoke16> xD
<FromGitter> <watzon> It's more of an experiment than anything, but I'd love to get it working
<hightower2> aha supposedly after I do changeset = Repo.insert(obj), then the object is in changeset.instance
lanodan has joined #crystal-lang
<hightower2> In Kemal, is it easy to re-reoute one route to another? Like, I have a route for /xyz, but would like / to do the same (i.e. execute the /xyz route)
<FromGitter> <Blacksmoke16> put logic in a method
<FromGitter> <Blacksmoke16> then could prob do like
<FromGitter> <Blacksmoke16> `get "/xys", ->method` and `get "/", ->method`
<FromGitter> <Blacksmoke16> something along those lines
<hightower2> mm, yes, yes, did so but still kept 2 or 3 lines within the route itself. I guess I could put everything in the method, yes. thanks
<FromGitter> <Blacksmoke16> 👍
livcd has quit [Remote host closed the connection]
<raz> hightower2: re ORM, jennifer seems the most mature atm
<raz> (i was in that spot a few weeks ago). crecto feels solid but painfully incomplete. granite sadly feels like a hack, even more incomplete.
<raz> clear looks promising (i'm hopeful) but seems to have some severe bugs (see issue tracker) and is a huge undertaking by apparently a single guy :(
<FromGitter> <watzon> Unfortunately clear also only supports Postgres iirc
<hightower2> yeah clear lacks some things
<raz> jennifer was the only one where i didn't bump into missing functionality or severe bugs so far. also a single-hero project (at first i thought it's even the same one who does clear, cause their english is very similar)
<FromGitter> <watzon> Avram is nice, but it's pretty closely tied to Lucky
<FromGitter> <Blacksmoke16> whats hacky about Granite?
<hightower2> we need a de-facto standard ORM
<raz> watzon: jennifer does postgres. even notify/listen.
<FromGitter> <watzon> I'm hoping they make some efforts to separate it a little more and provide documentation specific to avram
<raz> watzon: yea i had a peek at avram too. but had zero docs iirc.
<FromGitter> <Blacksmoke16> Granite could deff be improved by removing some kinda meh stuff and starting essentially from a simpler base
<FromGitter> <Blacksmoke16> i also like the concept of separating the querying/inserting logic from the actual model
<raz> Blacksmoke16: well, first of all nearly no docs. it also lacked a bunch of super basic functionality (can't remember what it was right now, iirc sth related to creating objects in memory)
<FromGitter> <Blacksmoke16> but some of that is tricky w/o reflection, i.e. how to set id
<raz> granite has the best migrator tho (micrate). so for me, micrate + jennifer it is at the moment.
<FromGitter> <Blacksmoke16> i mean there are a fair bit of docs? https://github.com/amberframework/granite/tree/master/docs and you can just do `model = User.new`
<FromGitter> <Blacksmoke16> always room for improvement, but i wouldnt say there are "nearly none"
<straight-shoota> clear docs are also pretty good: https://clear.gitbook.io/project/
<FromGitter> <watzon> What I need more than an ORM right now is a higher level way to manage concurrency
<FromGitter> <watzon> Man this is a pain in the ass
<raz> Blacksmoke16: sry, i don't remember what it was, i think it couldn't do transactions.
<FromGitter> <Blacksmoke16> it can, just not nicely :S
<FromGitter> <watzon> Yeah I've seen that haha. It's been there since 2018
<FromGitter> <Blacksmoke16> gotta do something dumb like `User.adapter.database.transaction do `
<straight-shoota> watzon, unfortunately, I didn't get around pushing further in that direction
<straight-shoota> Main point was I didn't have a practical use case for testing it
<straight-shoota> Or actually, I have https://github.com/straight-shoota/criss but it's not high in priorities :/
<raz> Blacksmoke16: welp, to me it was the sum of all things (i bumped into 2 or 3 before giving up). it may be fine for others who don't need these. jennifer just was the only one that gave me a close to AR experience without weird bugs or missing stuff.
<raz> not a fan of a bunch of jennifer things either. but the ORM-ecosystem in crystal doesn't give much choice yet, so i'm glad i found one that works at all :)
<raz> (i'd have much preferred crecto or clear, design-wise, but they were not in a usable state for me)
<straight-shoota> would be great to have an extensive comparison of available ORM shards which looks at the general design, but also goes into detail highlighting problems and innovative solutions
<raz> indeed. ideally something like a side-by-side comparison "how to do X in $orm".
<straight-shoota> And the same goes for other flooded markets like HTTP frameworks or CLI builders :D
<raz> http frameworks are easy. use kemal or build your own :P (until that new non-singleton kemal is ready or you're willing & able to drink the constraints of amber/lucky)
<straight-shoota> hehe
<straight-shoota> eventually the ecosystem will consolidate. There are simply not enough niches that there was a real necessity for having 5 major implementations competing for the same use cases
<straight-shoota> s/was/is/
<raz> oh i love the choices. none of them are mature enough for me personally yet, but they will get there
<raz> it's a great indicator for the splash that crystal is making. people want and do build in crystal!
<raz> basics just still need to shake down. e.g. basics like the pg-shard itself are buggy still. the only smtp shard would exit(0) the app on a network error until a few days ago, etc. ;)
<raz> and the ORMs are still understaffed
<straight-shoota> yes, it's great to see many people building their ideas into shards
<raz> crystal-core should funnel some of their donation millions into hiring an ORM team. but i understand those ferraris don't pay for themselves either :p
<straight-shoota> no, even the gas money adds up
<raz> yeh, i wasn't entirely serious about that one ;)
<FromGitter> <Blacksmoke16> gotta use that athena raz 😉
<FromGitter> <Blacksmoke16> i like to think its between kemal and amber/lucky. doesnt force anything on you, but more feature rich than kemal
<raz> Blacksmoke16: i had a look but not my cup of tea, sorry. :) i'm sure others will love it
<FromGitter> <Blacksmoke16> not much seems to be your cup of tea 😉
<FromGitter> <Blacksmoke16> ORM wise only requirement I have is to support annotations on your columns
<raz> yeh i'm very picky. in terms of web frameworks i don't want a reimpl of 10yr old patterns (sinatra / rails). i want sth that leverages the lovely crystal powers. lucky has that right but i disagreed with some choices, so ended up building basically my own lucky now
<FromGitter> <watzon> Oh?
<straight-shoota> which choice don't you agree with in lucky?
<raz> Blacksmoke16: for me it's reflection (being able to discover which columns exist etc. - to generate things like validation forms), transactions, notify/listen and a few other things. i def didn't mean to diminish any of the ORMs above. use-cases differ, so i'm sure of the others will work perfectly for many
<FromGitter> <Blacksmoke16> having columns support annotations would allow for that, as any shard could include a module and tap into ivars and such.
<FromGitter> <Blacksmoke16> but for sure. is quite hard to balance the needs/wants of everyone. prob why there are so many ORMs?
<raz> straight-shoota: too rigid (lucky-way or the highway), far too much boilerplate, inconsequential in some areas. (just my personal peeves). same as with ORMs, it's a great framework and surely works great for many. but after starting an app i realized i could do the same with 1/3 the LOC, so i went that route :)
<straight-shoota> yeah, I haven't looked at lucky deeply yet
<raz> might release mine one day, but that would be a major undertaking (writing docs etc.).
<straight-shoota> but from what I've seen, too rigid was my impression too
renich has joined #crystal-lang
<straight-shoota> docs will help you, too when you return to it after doing something else :D
<raz> no, i don't need no docs. crystal is amazing at making everything click into place with compile errors. even tho the macros make some of them non-obvious ;)
<straight-shoota> I know I often enough have to look up the documentation for things I've written at some point but can't remember
<FromGitter> <watzon> Same
<FromGitter> <Blacksmoke16> id be curious of hearing any specifics of what wasn't your cup of tea for Athena. not too many people using it so actual feedback isnt too common :p
<FromGitter> <Blacksmoke16> i.e. if anything could be made more clear in the docs, or API improvements etc
yxhuvud has quit [Read error: Connection reset by peer]
yxhuvud has joined #crystal-lang
<FromGitter> <Blacksmoke16> if its just general architecture np
<FromGitter> <watzon> That would be my advice. Good docs increase usage.
<FromGitter> <watzon> I highly recommend docasaurus
<straight-shoota> I guess one thing I'm not 100% comfortable with is the heavy use of annotations and macros. Not saying it's bad, it's actually a good idea and might be a great design for this kind of thing.
<raz> Blacksmoke16: yea, just different philosophies really. is there a good pastebin with crystal highlighting? hm
<straight-shoota> carc.in :D
<FromGitter> <Blacksmoke16> i like to think i document everything well. i think it could deff use some like cookbook/guide style ones. been trying to keep everything in the API docs for now just to avoid stuff getting out of date
<FromGitter> <watzon> I don't know of one that supports Crystal specifically. I use hastebin and just set the extension to .rb
<raz> heh, well, if it didn't chop off the code on the right... :P
<raz> watzon: hm yea, hastebin doesn't save for me atm :(
<raz> 503, seems their webserver is taking a nap
<FromGitter> <watzon> Hmm that's weird
<straight-shoota> Blacksmoke16: A getting started guide would be great. IIRC you had some articles on dev.to or so?
<FromGitter> <watzon> I use https://hasteb.in/
<raz> +1 on starter guide
<FromGitter> <Blacksmoke16> yea, goes thru setting it up with granite to make a blog
<FromGitter> <Blacksmoke16> been keeping it up to date
<raz> ohhh it works! i was on hastebin.com
<straight-shoota> That should be linked in the readme and API docs
<FromGitter> <watzon> It's FOSS software, so there are quite a few sites using the same thing
<FromGitter> <mattrberry> I'm a little confused about how macros and/or class getters/setters work. I'm trying to create something like
<FromGitter> <Blacksmoke16> straight-shoota: to be fair the macro usage isn't as widespread as you'd think, each core shard has like one major file that uses them, but really only part of athena core that uses it is for adding stuff to the router
<straight-shoota> Also I find it very weird that the API docs link ends up in a deep namespace
<FromGitter> <Blacksmoke16> hm?
<FromGitter> <Blacksmoke16> what about it? kinda just how the docs work since everything is under a global namespace
<FromGitter> <Blacksmoke16> and each component has their own namespace under that
<straight-shoota> Yeah I understand that
<FromGitter> <mattrberry> I'm a little confused about how macros and/or class getters/setters work. I'm trying to create something like ⏎ ⏎ ```@af = 0x1234``` ⏎ ⏎ would result in @a == 0x12 and @f == 0x34. ... [https://gitter.im/crystal-lang/crystal?at=5eb48b12347bd6163060a7ba]
<raz> blacksmoke16: in case you're curious, that's what my signup-form looks like: https://hasteb.in/nugarake.rb (threw in a snippet of the root component to show the routing etc.). that's the entirety of it (my boilerplate allergy is strong) and it generates a full form with client + server-side validation (unpoly js) etc. so conceptually it's very close to lucky, i just hadn't managed to bring lucky down to that level of verbosity.
<FromGitter> <Blacksmoke16> @mattrberry you're trying to declare ivars in the top level namespace
<straight-shoota> Blacksmoke16: It's just not clear how everything belongs together. athena looks like the main shard of the framework but its documentation link leeds to the routing component
<FromGitter> <mattrberry> @Blacksmoke16 I have that macro inside of a class
<FromGitter> <mattrberry> And the `define_register a, f` is also inside of the class
<FromGitter> <Blacksmoke16> so whats the problem exactly?
<FromGitter> <mattrberry> @a and @f are not being set
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/90zb ?
<FromGitter> <Blacksmoke16> seems fine to me
<FromGitter> <Blacksmoke16> you initialize them to `0_u8` so yea
<straight-shoota> mattrberry, the issue is `@af = 0x1234` is an assignment to an ivar
<FromGitter> <Blacksmoke16> straight-shoota: yea i could prob document that better. the thought is that `Athena` is the framework, but the framework itself is made up of various components, one of which is `Routing`.
<straight-shoota> it doesn't call the setter method you define in the macro
<FromGitter> <watzon> `{{upper.id}}{{lower.id}}` is smashing `a` and `f` together
<FromGitter> <watzon> So you're going to get `@af` not `@a` and `@f`
<FromGitter> <mattrberry> @straight-shoota How would I go about making those setters work?
<straight-shoota> `af = 0x1234`
<straight-shoota> or rather `self.af = 0x1234`
<FromGitter> <mattrberry> Ahh, so `self.af = ...` rather than `@af = ...` ?
<straight-shoota> exactly
<straight-shoota> the latter is a direct assignment to an ivar
<straight-shoota> you can't override that with a method
<straight-shoota> same with getters: `@a` directly accesses the ivar, `a` calls the getter (which typically returns `@a`)
<straight-shoota> watzon, how does your `html_for` helper work? Is it just DSL for the form block?
<FromGitter> <mattrberry> Awesome, thank you @straight-shoota and everyone for the help!
<straight-shoota> you're welcome
<FromGitter> <watzon> @straight-shoota where? Sorry I write a lot of code haha, I don't remember where `html_for` is.
<FromGitter> <Blacksmoke16> raz: yea it also helps i kinda been focusing on API side of things
<straight-shoota> ah, sry. I meant raz :D
<FromGitter> <watzon> Ahh ok lol
<straight-shoota> I had the hastebin open for a while
<straight-shoota> Regarding ORMs: I really don't like when query DSLs have pseudo SQL fragments expressed as literal Crystal code. Clear calls this expression engine.
<straight-shoota> Example: `.left_join(Passport) { _contact_id == _contact__id }` (Jennifer)
<straight-shoota> Example: `.where{ first_name == "Richard" }` (Clear)
<raz> straight-shoota: well, it's a component (everything is). yes, DSL by nature, but it's not static. it takes the a jennifer model as input and translates the fields to html form elements (or anything really, it uses type-based renderer classes). i.e. in that example it creates email-input or the email attr, passwords for the password, and takes care of all the validation, populating values after POST, adding the html attrs for client-side validation etc.
<raz> it even does the "passwords must match" thing etc. :)
<straight-shoota> raz: okay, so it's specific to the form builder. I was just wondering if it was a general helper which the name suggests. And for that it seems weird that it receives an object and property names
<FromGitter> <Uzay-G> What would be the best way to generate a secret token, like an api token, in crystal?
<straight-shoota> @Uzay-G you could use Random#base64 or Random#hex
<raz> straight-shoota: well it is general. html_for(u, "email", :input, ..) takes the User object (jennifer) and translates the "email" attr using the :input renderer. it can and does also take other things. (html_for is a bit of a misnomer, it's the renderer called 'input' that decides what actually comes out)
<straight-shoota> I guess then I would have expected :input to be the first argument :D
<straight-shoota> Thanks for clarifying
<raz> yea, well, all still wip. ;) if i ever release it will need docs and cleanups. it's just how i want to write web stuff. abstract all those nasty details away so i can focus on what matters, not re-write the same validation code a hundred times (and then re-write it again after adding another field :p)
<FromGitter> <Blacksmoke16> coughannotationscough 😉
<raz> Blacksmoke16: i like annos but didn't see a need. why annotate when the model already tells everything ¯\_(ツ)_/¯
<FromGitter> <Blacksmoke16> how does the model specify the validations in that example?
<FromGitter> <Blacksmoke16> some method on the class?
<raz> i just added some more stuff to the jennifer mapping def
<raz> BulmaInput is one of the renderer classes
<raz> basically you just write renderers for each attr type you have and for whatever CSS/JS framework you use
<raz> and then pick what is needed for each form (or it uses the default if not overridden)
<FromGitter> <Blacksmoke16> ah gotcha
<FromGitter> <Blacksmoke16> in this case our ideas arent too far off
<FromGitter> <Blacksmoke16> same general concept
<FromGitter> <Blacksmoke16> this is what my idea model would/could be
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5eb4935bb6dd230697b1add0]
renich has quit [Quit: renich]
<FromGitter> <Blacksmoke16> just so everything is an ivar/property, and assertions wouldnt be tied to a specific macro dsl
<raz> yup that looks great!
<raz> i didn't feel like wrapping jennifer with such (gonna be a royal pain)
renich has joined #crystal-lang
<raz> but it would be a great way to make it ORM agnostic. (my ties to jennifer aren't very strong, but i couldn't just swap it out atm either)
<FromGitter> <Blacksmoke16> (Granite supports that) 😉 is what i used for the blog tutorial https://github.com/Blacksmoke16/athena-blog-tutorial/blob/master/src/models/user.cr
<FromGitter> <Blacksmoke16> then you use serialize/validate your models directly, versus having separate things that are essentially just boilerplate
<raz> yap, can very much agree with that
<raz> except for one thing
<FromGitter> <Blacksmoke16> and since it uses annotations, its agnostic of what actual thing you use, versus tied to each specific orm or whatever
<raz> if i understand it right, you have to duplicate the model validations there?
<raz> (e.g. min-len on model *and* in annotation for form-generation)
<FromGitter> <Blacksmoke16> hm?
<FromGitter> <Blacksmoke16> ah you mean for validation and column creation?
<raz> yea, does @[Assert::NotBlank] only apply to the generated form
<raz> or also add the not-blank condition to when you try to validate/save the model instanec
<FromGitter> <Blacksmoke16> the validations are not really tied to the ORM, they're totally generic
<FromGitter> <Blacksmoke16> but they *could* be used in both
<raz> ok yea. it's not a big deal i think. but ideally validations should be declared only once
<raz> cause otherwise they can disagree, and we all know what then happens :p
<FromGitter> <Blacksmoke16> yea, also granted i havent done anything with forms yet
<FromGitter> <Blacksmoke16> so dont have any specific answers on that
<raz> ah gotcha. yap, my focus has been on this forms + validation thing from the start. cause over the past 10yrs i realized that's what i spend 95% of my webdev time in. basic CRUD nonsense that i just don't want to think about.
<FromGitter> <Blacksmoke16> kinda been basing my stuff on symfony, so like their example is
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5eb495020b23797ec06bfd42]
<FromGitter> <Blacksmoke16> where that class has
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5eb4951322f9c45c2a77c9cb]
<FromGitter> <Blacksmoke16> so i guess the form just knows about the validations on the ivars that map to fields
<FromGitter> <Blacksmoke16> ah, the submitted for exposes a `isValid()` method that runs the validations
<raz> yup, that looks about right. the one thing that most form builders don't do is to automatically add the right validations, field-len etc.
<raz> they want you to specify things like "min-len" on each form instance, which makes no sense to me. the model has a min-len, you never want to have a form with a different one.
<raz> (and i don't want to remember what the required constraints etc. are every time i write a form involving a user)
<FromGitter> <Blacksmoke16> mhm
<FromGitter> <Blacksmoke16> is what i like about the annotation approach, it provides an agnostic set of validations not tied to a particular part of your app
<FromGitter> <Blacksmoke16> instead of your form having its set, ORM having its set, etc
<raz> yea the important bits is that the constraints can be defined *once* and are not repeated anywhere.
<FromGitter> <Blacksmoke16> exactly
<raz> i'm not particularly married to where/how that definition happens, but model seems the natural place
<FromGitter> <Blacksmoke16> we been slowing moving our models to this type of approach, i.e. serializing/validating the models directly versus relying on other types for crud
<FromGitter> <Blacksmoke16> much more efficient
<raz> yep. i'm working on nested/incremental forms now (e.g. plus-button to add more instances of $item).
<FromGitter> <Blacksmoke16> also helps being able to use common interfaces for validating different things. I.e. the annotations you apply to your model could also be newed up directly and used in a form if its not worth having a model for
<FromGitter> <Blacksmoke16> or same validators for query params etc
<raz> that's where this approach saves hours and days of headaches
* raz nods
<raz> sounds like we're on the same html page :D
<raz> the next gen of crystal webframeworks is gonna be awesome. (even awesomer than the current batch)
<FromGitter> <Blacksmoke16> heh, im working on it 😉
<FromGitter> <Blacksmoke16> lol
<FromGitter> <Blacksmoke16> now just need to get you on board with the event approach hehe
<raz> yeh, you put all the work in with docs, actually releasing it etc. kudos to that!
<raz> oh, i'm using events. :p
<raz> (not for forms, but for everything else)
<FromGitter> <Blacksmoke16> now im even more curious what you meant by different philosophies
<raz> interesting you mention that, cause i haven't managed my head around how to use them for forms/model persistence.
<raz> ohhhh
<raz> that looks like a callback to me. with event i was thinking operation/kafka (operation in the lucky sense)
<FromGitter> <Blacksmoke16> prob for like altering form data/validating input etc
<FromGitter> <Blacksmoke16> ah gotcha
<raz> yea, i think that kind of event is nice, too. (for me it registers more as a "callback", terminology-wise :D)
<FromGitter> <Blacksmoke16> it gets the event name because the library that emits them calls them events
<FromGitter> <Blacksmoke16> i.e. it "emits" some event that other listeners can act upon (or not)
<raz> but i found it also gets in the way sometimes. e.g. sometimes i want to do extra stuff at POST-time, and events get in the way (wrong execution order, loss of variable scope)
<raz> but yes, having them is def a good idea
<FromGitter> <Blacksmoke16> depends on how you architect things, gets messy when they start to depend on eachother etc
<FromGitter> <Blacksmoke16> as you mention, specific orders and stuff
<raz> (my current take is that i want both. event-handler but also meaningful execution flow / return values so things can be wired up as needed)
<raz> yep, event-chaining is a slippery slope (cf. javascript)
<FromGitter> <Blacksmoke16> athena uses my event lib internally which allows for some of that, at least defining events/listeners, determining order they get executed in
<raz> onValidate, onSave are very nice in 99% of cases. just don't leave your users out in the cold in the 1% case where they really need basically only 1 line right in between the two ;)
<raz> (can't think of a good concrete example right now, but definitely been there :D)
<FromGitter> <Blacksmoke16> their event system works by you emit the event, and the listeners mutate it, then you get the event back in your code
<FromGitter> <Blacksmoke16> er the code that emitted the event
<raz> yup yup, when done right then at least in form-handling they can do everything that's needed i think. and it's a great pattern in general
<FromGitter> <Blacksmoke16> mhm, works well in framework land too, listeners can add/remove/alter response headers/cookies
<FromGitter> <Blacksmoke16> agnostic of eachother
<raz> well, that's where the lie starts :P
<raz> those terrible set-cookie headers...
<FromGitter> <Blacksmoke16> 🍪
<raz> (have to store the ones to be set in one place, but only later actually write them out)
<FromGitter> <Blacksmoke16> hm?
<raz> but yea, i see what you mean and agree with it :)
<raz> well, strictly speaking you can't "alter" a set-cookie in an event that may fire multiple times from anywhere
<raz> if it fires twice to set "foobar"-cookie twice, you have two headers
<FromGitter> <Blacksmoke16> sorry, to be clear i mean something like one listeners could override headers by other listeners
<FromGitter> <Blacksmoke16> like imagine some shard has a default thing, but you could define your own listener that runs after the default to change some values
<raz> yep, also sorry, that was too specific (can of course be solved). CookieJar just been sth i've been annoyed with recently
<FromGitter> <Blacksmoke16> (ofc would be better ways to handle that but you get the idea)
<raz> yup yup
<FromGitter> <Blacksmoke16> was one thing i noticed, headers get sent when you write to the response IO
<FromGitter> <Blacksmoke16> which can be quite hard to debug
Sharcho has quit [Quit: Leaving]
<raz> yea, i was getting too specific there. response IO can be tricky (with headers at all) when you want to write as you render to make it fast.
<raz> but that's kinda specific to the lucky-style render-method (html as code)
<raz> e.g. you've written a <title> a while ago. but now you want to change it (route went elsewhere).
<FromGitter> <Blacksmoke16> gl
<raz> yeh, that one ended up easy actually. fixed maxlen for title, remember offset, seek and overwrite :p
<raz> anyweh, pizza time. lookin forward to more athena in the future :)
<FromGitter> <Blacksmoke16> I'd think it would be right up your alley based on all this ha
<FromGitter> <Blacksmoke16> But I'll keep you posted, waiting on next crystal version ATM, till I can release some cool di stuff
<raz> maybe. prob not this version yet, but perhaps a future one. we just gotta keep writing these web frameworks till one of them is good enough so nobody bothers anymore :)
<FromGitter> <Blacksmoke16> Hehe
<straight-shoota> Maybe humankind will have advanced by that time so we don't use websites anymore
<straight-shoota> don't know what would be the successor, but might be some AI driven blockchain-to-brain interface