ChanServ changed the topic of #crystal-lang to: The Crystal programming language | http://crystal-lang.org | Crystal 0.30.1 | 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
<FromGitter> <fenicks> @j8r Regarding cross compilation, the resulted command should be run on the target device ?
teardown has quit [Ping timeout: 244 seconds]
<FromGitter> <tenebrousedge> which command?
<FromGitter> <tenebrousedge> the binary?
<FromGitter> <watzon> @fenicks yes
<FromGitter> <watzon> The command that the cross compilation flag gives you should be run on the target device
alex`` has quit [Ping timeout: 244 seconds]
lucasb has quit [Quit: Connection closed for inactivity]
chemist69 has quit [Ping timeout: 252 seconds]
<FromGitter> <sam0x17> is there a way to have multiple `method_missing` macros live at the same time in the same scope? It looks like the expression engine for Clear ORM uses a top-level `method_missing` macro, and I want to define my own `method_missing` macro at the top level but have it fall back to the existing Clear ORM one if my logic doesn't apply to the situation
chemist69 has joined #crystal-lang
<FromGitter> <sam0x17> something like: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5a1da4950718247706f461]
<FromGitter> <sam0x17> never mind, I found a workaround where I can just define the methods directly in the macro
ht_ has joined #crystal-lang
devil_tux has joined #crystal-lang
devil_tux has quit [Ping timeout: 245 seconds]
ht_ has quit [Quit: ht_]
absolutejam has quit [Ping timeout: 268 seconds]
rohitpaulk has joined #crystal-lang
rohitpaulk has quit [Remote host closed the connection]
sorcus has quit [Ping timeout: 250 seconds]
devil_tux has joined #crystal-lang
flaviodesousa has joined #crystal-lang
<FromGitter> <absolutejam_gitlab> Is there a way to define an 'else' for an `enum`?
<FromGitter> <absolutejam_gitlab> Like ⏎ ⏎ ```enum Foo ⏎ Success ⏎ else Fail ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5a56c2d03a7c63e657bce6]
<FromGitter> <absolutejam_gitlab> tackling this a different way, nvm
_whitelogger has joined #crystal-lang
<FromGitter> <absolutejam_gitlab> Should the compiler complain that a method based on an abstract method does not conform to the return type?
<FromGitter> <watzon> @absolutejam_gitlab as of 0.30.0 yes
<FromGitter> <absolutejam_gitlab> Hm
<FromGitter> <absolutejam_gitlab> I'll test because I'm sure it didn't catch them as I expected
<FromGitter> <j8r> @absolutejam_gitlab note you can have method in an enum
sorcus has joined #crystal-lang
<FromGitter> <fenicks> @watzon Thanks I'll try on target device.
alex`` has joined #crystal-lang
alex`` has quit [Ping timeout: 248 seconds]
alex`` has joined #crystal-lang
<FromGitter> <absolutejam_gitlab> `HTTP::Client` doesn't have in-built JSON support?
<FromGitter> <absolutejam_gitlab> halite it is then
<FromGitter> <andrius> I want to build crystal classes from the swagger-based API; that is a kind of ruby-like rake task. Class definitions would be rendered from the template, so question: what is better to use for such task (as far I understand, ECR would work only at compile time, and something else should be used? )
<FromGitter> <absolutejam_gitlab> I'm working on the same atm
<FromGitter> <absolutejam_gitlab> I'm literally just building up objects then parsing those objects as text into files
<FromGitter> <absolutejam_gitlab> So, read the YAML into Swagger objects that I have defined. Iterate over the endpoints & resources, create some objects for these and then iterate over them and spit them out to files
<FromGitter> <andrius> hmm
<FromGitter> <andrius> that's is not my code, I just use that library with ruby and want just to port to crystal and it is very DRY-like (your path also fine, I already generated code or another Asterisk interface, AMI)
<livcd> oh god I had such an urge to use Crystal...sadly it's not available on Windows
<FromGitter> <Blacksmoke16> @absolutejam_gitlab be sure to turn on warnings
<FromGitter> <Blacksmoke16> abstract def return types are just warnings atm
lucasb has joined #crystal-lang
duane has quit [Ping timeout: 272 seconds]
<FromGitter> <j8r> I'm working on fast-json, a limitation would be the absence of `Builder#start_document` and `Builder#end_document`, which require to store the state in an Array
<FromGitter> <j8r> yes this one
<FromGitter> <j8r> there would be only `Builder#document &block`
<FromGitter> <j8r> which is fine, no?
<FromGitter> <Blacksmoke16> oh, you mean in `fast-json`
<FromGitter> <j8r> yes, I'm merging the stdlib json, with my CON format builder
<FromGitter> <Blacksmoke16> if you support the block wouldnt it be easy to support the others?
<FromGitter> <Blacksmoke16> since stdlib block version uses start/end
<FromGitter> <j8r> the stdlib use an Array of states, in order to prevent errors
duane has joined #crystal-lang
<FromGitter> <j8r> for example doing `start_document` 2 times
<FromGitter> <Blacksmoke16> ah gotcha
<FromGitter> <Blacksmoke16> but wouldnt need it for the block version since it would be known when each is done
<FromGitter> <j8r> thinking...
<FromGitter> <Blacksmoke16> i mean if you do like
<FromGitter> <Blacksmoke16> ```builder.document do ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5aa2c9beba830fffc2b3d4]
<FromGitter> <Blacksmoke16> you dont have to worry about someone opening but not closing it
<FromGitter> <j8r> in fact I know
<FromGitter> <j8r> why the block is needed
<FromGitter> <j8r> because in my implementation, the state is stored in ivars
<FromGitter> <j8r> like ⏎ ⏎ ```@root_document = false ⏎ @begin_hash = false ⏎ @begin_array = false``` [https://gitter.im/crystal-lang/crystal?at=5d5aa3044e17537f526067c5]
<FromGitter> <Blacksmoke16> hows that work if you do like
<FromGitter> <Blacksmoke16> ```builder.array do ⏎ builder.array do ⏎ end ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5aa3231db76d0ffe01ef7c]
<FromGitter> <Blacksmoke16> wouldnt the 2nd array reset the value while still in the first array
<FromGitter> <j8r> so in your example
<FromGitter> <j8r> reset what value?
<FromGitter> <Blacksmoke16> `@begin_array`
<FromGitter> <Blacksmoke16> is i imagine in the start of the block you're setting that to true, then in an `ensure` setting it to false?
<FromGitter> <j8r> yes, before `yield` set to true, then false
<FromGitter> <Blacksmoke16> right so after the inner block is done the ivar would be false
<FromGitter> <Blacksmoke16> even tho its still in the outer block, which could still do other stuff
<FromGitter> <j8r> I think I need to rework a bit, to store the previous state
<FromGitter> <absolutejam_gitlab> @Blacksmoke16 probably that which I missed
<FromGitter> <j8r> just the previous one, yield, then restore it
<FromGitter> <absolutejam_gitlab> I'm just doing `crystal run` too
<FromGitter> <Blacksmoke16> @absolutejam_gitlab `crystal run --warnings all` should do it
<FromGitter> <absolutejam_gitlab> ty
<FromGitter> <Blacksmoke16> im assuming you're not using the array for performance reasons?
<FromGitter> <j8r> yes
<FromGitter> <j8r> it's working, but I suspect there are check missing like you said
<FromGitter> <Blacksmoke16> write up some specs so you know its working as you mess with it
<FromGitter> <j8r> yes I do
<FromGitter> <Blacksmoke16> 💯
<FromGitter> <j8r> lot's of, I need more for that raise errors
<FromGitter> <j8r> Or, we can be fine to eventually output wrong JSON if we use it wrong, for more perf
<FromGitter> <Blacksmoke16> depends what your goal is
<FromGitter> <Blacksmoke16> i.e. ignore safety for speed, or balance between safety and speed
<FromGitter> <j8r> at least, the `Object#to_con` and `Object#to_json` is faster and as safe
devil_tu1 has joined #crystal-lang
<FromGitter> <j8r> this checks are mainly for the user using it directly
<FromGitter> <Blacksmoke16> having something more advanced that allows for more performance prob is fair
devil_tux has quit [Ping timeout: 248 seconds]
<FromGitter> <j8r> I tested, we can have directly an array inside a hash :/
<FromGitter> <Blacksmoke16> 😬
<FromGitter> <j8r> agree @Blacksmoke16 , and it's only unsafe when using it directly
<FromGitter> <j8r> not when using `Any`, `Serializable` or `mapping`
<FromGitter> <j8r> excluding the unsafe builder, I have a safe JSON::Parser alternative
<FromGitter> <j8r> with don't use Token
<FromGitter> <Blacksmoke16> nice one
<FromGitter> <Blacksmoke16> been refactoring crserializer lately, thought of a better implementation, but trying to think thru the API a bit
<FromGitter> <Blacksmoke16> mainly want to come up with a good method to sharing common logic, and support some custom exclusion annotations the user can define
<FromGitter> <absolutejam_gitlab> Is there a class name limit?
<FromGitter> <absolutejam_gitlab> *length
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/7fal doesnt look like it
<FromGitter> <absolutejam_gitlab> Hm, okay
<FromGitter> <Blacksmoke16> why?
<FromGitter> <absolutejam_gitlab> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5aab9953490e334d22118f]
<FromGitter> <absolutejam_gitlab> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5aaba6c87a0963e79ff065]
<FromGitter> <absolutejam_gitlab> Just suddenly started after I'm elbow deep in yaml
<FromGitter> <Blacksmoke16> pretty sure the mapping overrides the initializer on the parent
<FromGitter> <kniknoo> Still tying to wrap my head around a union. I'm still learning to parse and codegen. For the project I'm currently on, I have my parser doing some lex work. Up until now I've been able to use a numerical system and return a number per command type, followed by optional numerical parameters in its own array. Now I'm adding a label interpreter which will need to send the name of the label. What do I need to set
<FromGitter> ... up as a type so that I can include strings depending on the first value? No matter what I do, something stops me from making a type that doesn't care if there's a string. Should I maybe set up a global symbol table and let the parser set it and the codegen look it up instead of trying to force the union?
<FromGitter> <absolutejam_gitlab> wonder if it's the parent
<FromGitter> <absolutejam_gitlab> it has ` type: Array(Docker::Swagger::Path::Action::Parameter | ⏎ ⏎ `````` [https://gitter.im/crystal-lang/crystal?at=5d5aabe31db76d0ffe023d7c]
<FromGitter> <absolutejam_gitlab> Not sure if that's valid
<FromGitter> <Blacksmoke16> try using the serializable stuff vs the mapping
<FromGitter> <Blacksmoke16> but if those are separate things, then yea that could be it
<FromGitter> <absolutejam_gitlab> sorted it
<FromGitter> <absolutejam_gitlab> merged the type slightly
<FromGitter> <Blacksmoke16> 👍
<FromGitter> <tenebrousedge> @kniknoo I don't know about anyone else, but I have no idea what you're asking
<FromGitter> <j8r> got an idea
<FromGitter> <j8r> We could have `builder.document` that yield an `JSON::DocumentObject`, which doesn't have several methods like `array`
<FromGitter> <j8r> same for array, `JSON::ArrayObject`
devil_tu1 has quit [Ping timeout: 268 seconds]
<FromGitter> <j8r> that's a false good idea, because the user can still do sh**
<FromGitter> <Blacksmoke16> 😢
<FromGitter> <kniknoo> Oh dear, I'll try again. My parser returns typically something like [[2, 0, 5],[4]] for "pop constant 5" "add". But now I would need to return like [[11, "label"]] for "label labelname". Crystal doesn't seem to like Array(Array(Int32 | String)) and with Array(Array(Int32) | Array(Int32 | String)) it tries to process the numbers as strings. I'm trying to make a structure that comes out [[Int32, String]] . In the
<FromGitter> ... end, I'm really really terrible at pattern matching so I'm just trying to make everything number based for keywords.
<FromGitter> <yxhuvud> My recommendation is to instead return [{Int32,String}]
<FromGitter> <yxhuvud> ie, let the composite pairs be a tuple
<FromGitter> <kniknoo> Okie doke. With a tuple I'll need a single layout though, right? There isn't a way to get [{Int32, String} | {Int32, Int32} | {Int32 | Int32 | Int32}] is there? The more possibilities there are for the number of return values, the more I think I need to rethink how this is going to work.
<FromGitter> <asterite> I think you should use types instead of nested arrays and tuples
<FromGitter> <asterite> and there's the `record` macro which simplifies things further
<FromGitter> <asterite> then "pattern maching" becomes checking against a type name, which is even more readable in my opinion
devil_tux has joined #crystal-lang
<FromGitter> <kniknoo> I'm reading the record macro info. May take some time to sink in. I'm trying to understand what you mean by using types. Like send a hash for each line with everything labelled?
<FromGitter> <asterite> Like using a class or a struct with a name instead of unnamed arrays and tuples
<FromGitter> <asterite> Like, what's [11, "label"]? No idea. But make it `Instruction.new(opcode: 11, label: "label")` and it's so much clearer
<FromGitter> <kniknoo> Gotcha!
ht_ has joined #crystal-lang
<FromGitter> <kniknoo> Nice! I'm getting the hang of this. Thank you!
<FromGitter> <shdown> So, the crystal compiler v0.30.0 segfaults when I try to build a specific code base. Ho do I debug it?
<Yxhuvud> shdown: you try to isolate the problem as far as you can, then you file a bug report with your findings.
<Yxhuvud> You probably also want to find a more modern version, 0.30.1 is out. Use that, and see if you still get the issue
shdown has joined #crystal-lang
<shdown> I am unable to build Crystal on my machine since the build process seems to eat up all the memory (4G).
shdown has quit [Remote host closed the connection]
<FromGitter> <shdown> OK, Crystal 0.30.1 [5e6a1b672] segfaults too.
<FromGitter> <j8r> shdown, if your are on linux you can try activating zwap
<FromGitter> <j8r> building LLVM consume less memory lol
<FromGitter> <shdown> I know, I have built LLVM myself on this machine :)
<Yxhuvud> last time I tried building llvm from scratch it gobbled up all my 16GB and then died.
<Yxhuvud> so I don't know about that ;)
<FromGitter> <shdown> Yxhuvud, that probably was the “Debug” version.
flaviodesousa has quit [Quit: KVIrc 4.9.3 Aria http://www.kvirc.net/]
DTZUZU has quit [Read error: Connection reset by peer]
duane has quit [Ping timeout: 268 seconds]
shdown has joined #crystal-lang
<FromGitter> <j8r> I'm compiling LLVM on qemu aarch64 with assertions enabled
<FromGitter> <j8r> damn long
<FromGitter> <shdown> OK, I kinda reduced it to this: https://github.com/shdown/crystal-segfault
<FromGitter> <shdown> Now it says, “BUG: trying to assign Nil <- Isekai::DFGExpr+ (Exception) ⏎ from ??? […]”
devil_tux has quit [Ping timeout: 246 seconds]
<FromGitter> <j8r> It still needs to be reduced @shdown
<FromGitter> <shdown> OK, trying to do that
devil_tux has joined #crystal-lang
<FromGitter> <kinxer> Not strictly Crystal-related, but has anyone here ever written a REST API wrapper?
shdown has quit [Remote host closed the connection]
DTZUZO has joined #crystal-lang
rohitpaulk has joined #crystal-lang
<FromGitter> <tenebrousedge> yeah
<FromGitter> <absolutejam_gitlab> Is there any way to get random access to AST nodes without using the parser lib
<FromGitter> <Blacksmoke16> are any of you guys' CI failing on nightly due to stdlib deprecations?
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5ae5b00eff7d2dfedca8ba]
<FromGitter> <Blacksmoke16> prob from the recent hash changes, cc @asterite
rohitpaulk has quit [Ping timeout: 246 seconds]
devil_tux has quit [Ping timeout: 258 seconds]
dannyAAM has quit [Quit: znc.saru.moe : ZNC 1.6.2 - http://znc.in]
dannyAAM has joined #crystal-lang
<FromGitter> <kinxer> @tenebrousedge What have you found to be the best way to create objects from queries that reference them but don't give all their information? For example, if I'm looking at bus transit information and I send a GET for data about a given bus route, it might reference stop `E11`, but I can also GET data about the stop itself, and that will give info about things like the stop's street address. If someone is using
<FromGitter> ... the API wrapper and gets a `BusRoute` object, should that contain a `BusStop` object that's only partially filled out or should it include only a string of the bus stop's reference code?
<FromGitter> <tenebrousedge> @kinxer usually I would expect to get the more limited subset, by default
<FromGitter> <tenebrousedge> but you could maybe have an argument to change the behavior
<FromGitter> <tenebrousedge> or a different method to retrieve it
<FromGitter> <Blacksmoke16> then have a `bus_stop` method that does the call and returns a `BusStop` object based on the reference code on that `BusRoute`
<FromGitter> <Blacksmoke16> yea
<FromGitter> <absolutejam_gitlab> Use graphql 😏
<FromGitter> <tenebrousedge> I think my ideal in that situation would be to have it be a lazily-evaluated reference
<FromGitter> <Blacksmoke16> could also setup the getter to do the query if its not already set, otherwise return the set version
<FromGitter> <tenebrousedge> ^
<FromGitter> <Blacksmoke16> like
<FromGitter> <Blacksmoke16> ```def bus_stop ⏎ @bus_stop || = @client.get_bus_stop @bus_stop_id ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5aed4f029a51607fc74975]
<FromGitter> <Blacksmoke16> something like that
<FromGitter> <tenebrousedge> 👍
<FromGitter> <kinxer> Those are good idea. Thanks, y'all!
<FromGitter> <Blacksmoke16> er better yet
<FromGitter> <Blacksmoke16> ```class BusRoute ⏎ ... ⏎ getter bus_stop { @client.get_bus_stop @bus_stop_id } ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5aeddb0eff7d2dfedce99d]
<FromGitter> <Blacksmoke16> `If a block is given to the macro, a getter is generated with a variable that is lazily initialized with the block's contents:`
<FromGitter> <kinxer> Do you have every class initiated with `Client`?
<FromGitter> <kinxer> Or does each instance have its own `Client` instance?
<FromGitter> <Blacksmoke16> depends how you set it up
<FromGitter> <Blacksmoke16> IMO id rather use DI and inject a common client into any class that needs it
<FromGitter> <Blacksmoke16> others would new it up in every class
<FromGitter> <Blacksmoke16> or could use a class method on a module like `ClientFactory.get_client`
<FromGitter> <Blacksmoke16> would at least make it so you dont duplicate the same code everywhere, esp if it has other dependencies
<FromGitter> <tenebrousedge> is the `client` stateful?
<FromGitter> <kinxer> The client I currently have is instantiated but not stateful. I'm leery of making it into a Singleton, though (and I'm not sure I even can since I am, alas, working in Java).
<FromGitter> <tenebrousedge> I don't know enough about Java to comment
<FromGitter> <kinxer> That's fair.
<FromGitter> <Blacksmoke16> crystal singleton would just be like `CLIENT = Client.new`?
<FromGitter> <Blacksmoke16> then just use the const everywhere?
<FromGitter> <kinxer> For a Crystal singleton, I'd use class methods and variables to have global state.
<FromGitter> <tenebrousedge> I mean, if it's not stateful, then a module method would work just as well as anything else
<FromGitter> <Blacksmoke16> without taking on additional shards, the factory class method would prob be good. dont have to make it a singleton, can new one up every time its called
<FromGitter> <kinxer> I've actually done that before, though I recently refactored it into a non-singleton.
<FromGitter> <kinxer> Yeah, I do like the factory approach.
<FromGitter> <Blacksmoke16> i approve :P not full DI, but deff better than just newing them up adhock
<FromGitter> <Blacksmoke16> if you want to make testing easier as well you could do something like https://www.rubypigeon.com/posts/dependency_injection_containers_vs_hardcoded_constants/#the-hybrid-approach
<FromGitter> <Blacksmoke16> or in Crystal's case, do `self.new`, then could still pass mocked dependencies in your tests, while all other cases would use the default ones from your module
<FromGitter> <bew> @absolutejam_gitlab what do you mean by "random access to AST nodes" ? (I would say no, but it actually depends on what you want to do)
<FromGitter> <absolutejam_gitlab> Sorry, yeah, bit vague
<FromGitter> <absolutejam_gitlab> So, say I wanted to do `foo() some_macro` where `some_macro` can access `foo()`
<FromGitter> <absolutejam_gitlab> the examples I've seen use string blocks of code and the parser, but I'm thinking kinda like how macros inject AST in-place, can you also pull random bits of surrounding AST out?
<FromGitter> <Blacksmoke16> got a more complete example?
<FromGitter> <absolutejam_gitlab> Essentially, could you implement the pipe operator
<FromGitter> <absolutejam_gitlab> `foo |> bar(2)` == `Bar(foo, 2)`
<FromGitter> <Blacksmoke16> ah, was going to say you can do `@def` in a macro which returns a `Def` object based on the method the macro is currently in
<FromGitter> <sam0x17> @Blacksmoke16 I thought you might be the person to ask this -- would you say I am correctly portraying `has_many: :through`relations here: https://github.com/anykeyh/clear/issues/87#issuecomment-522697103
<FromGitter> <absolutejam_gitlab> Only just found `.first?` ffs
<FromGitter> <Blacksmoke16> :S
<FromGitter> <sam0x17> the shard author never replies anything so I wanted someone's reaction before I waste time making a fork/pull request
<FromGitter> <sam0x17> I'm starting to wish I had just gone with granite but I'm too deep now so might as well fix things as I go along
<FromGitter> <Blacksmoke16> :/
<FromGitter> <wontruefree> I have not checked out clear for a while. Is clear pretty API stable?
<FromGitter> <Blacksmoke16> yea i dunno, my brain hurts thinking about relationships like this :p
<FromGitter> <Blacksmoke16> never really touched that part of Granite, other than some minor cleanup around the macros
<FromGitter> <wontruefree> is there a generic relational algerbra lib for crystal
<FromGitter> <wontruefree> is something like that even a good idea
ht_ has quit [Quit: ht_]
<FromGitter> <sam0x17> I'd say stay away from clear. I just spent an entire day extending it so I can get the equivalent of `.attributes` in rails. Clear has .to_h on models, but it uses the native db column types instead of the crystal types, which is useless
<FromGitter> <Blacksmoke16> `.attributes`? whats that do
<FromGitter> <sam0x17> the expression engine is also very scary / glitchy, as it is built using a top-level `macro method_missing`
<FromGitter> <sam0x17> gives you a hash of the model
<FromGitter> <wontruefree> I really like clear about a year ago when I used it
<FromGitter> <Blacksmoke16> ah
<FromGitter> <Blacksmoke16> granite has that :P
<FromGitter> <Blacksmoke16> and now natively supports annotations
<FromGitter> <sam0x17> yeah but granite is fine I've used it before without issue
<FromGitter> <sam0x17> (when I cared about mongo) I based mongo_orm on granite and found the source code easy to work with
<FromGitter> <wontruefree> I used granite for my first crystal app
<FromGitter> <wontruefree> and it was hard to support jsonb
* FromGitter * Blacksmoke16 will be doing a blog post soon that will mention some of the benefits of the annotation support
<FromGitter> <sam0x17> the real pain point tho, in almost every system except I guess amber itself is migrations
<FromGitter> <sam0x17> none of the migration shards seem to care about things like `db:drop` `db:create` which baffles me
<FromGitter> <sam0x17> so I end up re-writing the CLI as a Cakefile
<FromGitter> <wontruefree> does amber have a solution for migrations?
<FromGitter> <sam0x17> it basically works like rails
<FromGitter> <sam0x17> uses `micrate` internally
<FromGitter> <sam0x17> but the amber CLI methods are really good
<FromGitter> <sam0x17> whereas if you try to just drop `micrate` in a project it doesn't support all the same things
<FromGitter> <sam0x17> if you don't care about `db:drop` and `db:create` and are ok with configuring some paths it's painless
<FromGitter> <sam0x17> but I care about that
<FromGitter> <Blacksmoke16> converter support was recently added, which can serialize an obj to a `JSON` column on save, but then deserialize it back into an obj on read
<FromGitter> <absolutejam_gitlab> is there a more concise way of doing `.select.map`?
<FromGitter> <Blacksmoke16> i never viewed migrations as a big enough pain, always been easier to just run the sql directly
<FromGitter> <wontruefree> Thanks @Blacksmoke16. It is awesome that was added
<FromGitter> <Blacksmoke16> granted i never had more than a few tables so far
<FromGitter> <sam0x17> yeah, working with a 5 year old rails app with over 1000 migration files
<FromGitter> <Blacksmoke16> @wontruefree https://github.com/amberframework/granite/blob/master/docs/models.md#converters are the docs on it
<FromGitter> <Blacksmoke16> also supports custom ones
<FromGitter> <sam0x17> I had to jump start it into using clear by writing a migration on the rails side that creates the `versions_cr` table that `migrate` uses (the migration shard I'm using) and tricks it into thinking the first migration (which is basically a ported copy of schema.db) has already run
<FromGitter> <wontruefree> that is big step forward
<FromGitter> <Blacksmoke16> @absolutejam_gitlab could maybe use https://crystal-lang.org/api/master/Enumerable.html#compact_map(&block)-instance-method
<FromGitter> <Blacksmoke16> and do like `condition ? v : nil`
<FromGitter> <sam0x17> ah stop you are just making me wish I switch to granite this second lolol
<FromGitter> <Blacksmoke16> id be curious to see a benchmark comparing that vs `select.map`
<FromGitter> <Blacksmoke16> :P
<FromGitter> <sam0x17> I should have used it lol
<FromGitter> <Blacksmoke16> code is still pretty meh, needs another cleanup pass
<FromGitter> <sam0x17> I stupidly saw that amber community had taken the shard over and stupidly thought that meant it is on life support
<FromGitter> <Blacksmoke16> much much better than it was before tho using mutable constants and such
<FromGitter> <Blacksmoke16> have some other plans mainly focused around its migrator, but not very high on my todo list
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b04ba029a51607fc801a1]
<FromGitter> <Blacksmoke16> something like that
DTZUZO has quit [Ping timeout: 258 seconds]
DTZUZO has joined #crystal-lang
<FromGitter> <sam0x17> is there something like a `model.reload` method in granite? @Blacksmoke16 -- I'm giving a go at converting to granite
<FromGitter> <sam0x17> gonna try this and hope it works for now: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b1d10bb5364334c654bd9]
<FromGitter> <Blacksmoke16> What's the point of it?
<FromGitter> <sam0x17> to reload the model if you know something has changed because of external circumstances
<FromGitter> <sam0x17> also very useful in specs
<FromGitter> <sam0x17> also from what I can tell there isn't transactions w/rollback support?
<FromGitter> <Blacksmoke16> There kinda is
<FromGitter> <sam0x17> I'm using an extension of crystal spec that allows me to do `around_each` and right now I wrap each spec in a `Clear::SQL::Transaction do` block using `around_each`
<FromGitter> <Blacksmoke16> i think you can do like
<FromGitter> <Blacksmoke16> ```Model.adapter.transaction do |tx| ⏎ ... ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5b20d395071824770febd5]
<FromGitter> <Blacksmoke16> that *should* work but i havent tested it
<FromGitter> <sam0x17> gotcha
<FromGitter> <Blacksmoke16> er sec
<FromGitter> <Blacksmoke16> ```Model.adapter.database.transaction do |tx| ⏎ ... ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d5b21c47d56bc6080880e67]
<FromGitter> <Blacksmoke16> that one
<FromGitter> <sam0x17> yeah typically you run into problems when there is nesting as at least with postgres that has to be handled specially using the SAVEPOINT mechanism
<FromGitter> <sam0x17> gotcha
<FromGitter> <Blacksmoke16> just calls the crystal-db transaction thing
<FromGitter> <sam0x17> hats off by the way to granite for correctly implementing `to_h`
<FromGitter> <sam0x17> oh then it might be nestable then
<FromGitter> <Blacksmoke16> pretty sure it is
<FromGitter> <sam0x17> nice
<FromGitter> <absolutejam_gitlab> I want to look at using annotations more
<FromGitter> <absolutejam_gitlab> I like the style
<FromGitter> <absolutejam_gitlab> the spec I'm working with can either have ⏎ ⏎ ```properties: ⏎ Bar: ⏎ Something: "a" ⏎ Baz: ⏎ Something: "a"``` [https://gitter.im/crystal-lang/crystal?at=5d5b284253490e334d263c4a]
<FromGitter> <absolutejam_gitlab> And I'm trying to convert from YAML
<FromGitter> <absolutejam_gitlab> I tried `YAML.mapping` with `properties: {key: "properties", type: Hash(String, SomeType) | SomeType}` but it is defaulting to the wrong type
<FromGitter> <Blacksmoke16> ayy annotations
<FromGitter> <absolutejam_gitlab> eg. the 2nd one (which should be `Hash(String, SomeType)`) is being parsed as `SomeType` with all `nil`
<FromGitter> <absolutejam_gitlab> I know you can manually parse properties, but is there some magic to how it's detected? Should I define a `to_yaml` and figure out the type?
<FromGitter> <Blacksmoke16> hmm
<FromGitter> <Blacksmoke16> what if you do two separate properties with diff types
<FromGitter> <Blacksmoke16> naw that wont work
<FromGitter> <Blacksmoke16> yea i dont have a good answer
<FromGitter> <absolutejam_gitlab> I blame the spec. Why have this in a spec, why not have a single key haha
<FromGitter> <absolutejam_gitlab> Hash
<FromGitter> <Blacksmoke16> swagger spec?
<FromGitter> <absolutejam_gitlab> Yeha
<FromGitter> <absolutejam_gitlab> Yeah
<FromGitter> <Blacksmoke16> is one deprecated?
<FromGitter> <absolutejam_gitlab> No, it's in the same file
<FromGitter> <Blacksmoke16> ah rip
<FromGitter> <Blacksmoke16> gl :P
<FromGitter> <Blacksmoke16> wanna see some cool annotation magic i did?
<FromGitter> <bew> I do :)
<FromGitter> <Blacksmoke16> alright, so. for my validation shard
<FromGitter> <Blacksmoke16> (going to split it out into its own shard soon)
<FromGitter> <Blacksmoke16> the whole premise of it, is you can do
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b2c89bfd2887f53207805]
<FromGitter> <Blacksmoke16> such that
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b2ca19507182477104405]
<FromGitter> <Blacksmoke16> each assertion consists of:
<FromGitter> <Blacksmoke16> an annotation that is applied to the property
<FromGitter> <Blacksmoke16> a "handler" class that implements the logic
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b2d230eff7d2dfedefb29]
<FromGitter> <Blacksmoke16> like so
<FromGitter> <Blacksmoke16> After https://github.com/crystal-lang/crystal/pull/7694 was merged, it allowed for much cooler stuff
<FromGitter> <Blacksmoke16> because you can do
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b2d6e7d56bc608088689d]
<FromGitter> <Blacksmoke16> i.e., for each ivar, iterate over each assertion class, if that ivar has that assertion's annotation, new up an assertion and push it to an array
<FromGitter> <Blacksmoke16> they key here being `ann.named_args.double_splat`
<FromGitter> <Blacksmoke16> all the ivars in each assertion's initializer maps to the field you define on the annotation
cerulean has joined #crystal-lang
<cerulean> hey
<cerulean> is there a Kemal channel?
<FromGitter> <Blacksmoke16> https://gitter.im/sdogruyol/kemal
<FromGitter> <Blacksmoke16> so what that means is, 1) it wont compile if you miss a required annotation field (ivar w/o a default value), 2) it wont compile if you use the wrong type as that field's value, and 3) defining custom assertion is as easy as the user can define all of this by just making a class extend from a parent
<FromGitter> <Blacksmoke16> the end
<FromGitter> <bew> So cool use of annotations
<FromGitter> <Blacksmoke16> thanks :) im quite pleased at it
<FromGitter> <Blacksmoke16> much much better than the previous implementation
<FromGitter> <bew> Although you could go farther, and not require the `value` arg being named but positional in the ann
<FromGitter> <bew> And allow positional & named args in the asserts
<FromGitter> <Blacksmoke16> possibly yea ` @[Assert::GreaterThanOrEqual(0)]`
<FromGitter> <bew> Yeah that
<FromGitter> <Blacksmoke16> thats an option
<FromGitter> <Blacksmoke16> well no, theres a problem i think with that
<FromGitter> <Blacksmoke16> maybe
<FromGitter> <Blacksmoke16> some assertions dont have a value you have to provide
<FromGitter> <bew> About the usage, I'm not sure why you need a separate call to `validate`
<FromGitter> <Blacksmoke16> in the example?
<FromGitter> <bew> Y
<FromGitter> <Blacksmoke16> performance, only runs the annotations once
<FromGitter> <Blacksmoke16> then caches the result
<FromGitter> <Blacksmoke16> otherwise every time you use `.valid?` would have to rerun them
<FromGitter> <bew> Yeah but then it's too easy to desynchronise the validation result and the actual values (e.g see the 2nd call to valid? which is wrong
<FromGitter> <bew> )
<FromGitter> <Blacksmoke16> suppose it could be optional arg to valid?
<FromGitter> <bew> Hmmaybe, would need some real code to see how when it's used
<FromGitter> <Blacksmoke16> i mainly created it to use in athena
<FromGitter> <Blacksmoke16> i.e. you do a POST request, deserializes JSON body into an object, runs validations, if its not valid, return 400 with errors
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b31850eff7d2dfedf1d59]
<FromGitter> <Blacksmoke16> like so
<FromGitter> <bew> You don't need any validation caching in that case, do you?
<FromGitter> <Blacksmoke16> not really no
<FromGitter> <bew> From a user perspective, doing `valid?` after modifying a field should redo the validations imo
<FromGitter> <bew> And not doing any caching
<FromGitter> <bew> Unless you add more code to kinda detect that a field has been changed (not trivial at all..)
<FromGitter> <bew> ⏎
<FromGitter> <bew> Not sure what you mean by "some assertions dont have a value you have to provide"
<FromGitter> <Blacksmoke16> `@[Assert::NotNil] `
<FromGitter> <Blacksmoke16> like there isnt a value to compare or anything
<FromGitter> <Blacksmoke16> i mean it would be doable, but would complicate the code a bit since you'd have to do some more checking
<FromGitter> <Blacksmoke16> and yea i think having a changeset there and caching if nothing changed, and only rerun changed properties would be best case senario
<FromGitter> <bew> You mean in the generation of the `MyNotNilChecker.new(, field: "a", actual: nil)` the problem is be the first comma, right
<FromGitter> <bew> ?
<FromGitter> <Blacksmoke16> with some refactoring might be doable, as if you cache the assertions you could easily also values
<FromGitter> <Blacksmoke16> yea, im thinking that wouldnt compile?
<FromGitter> <bew> No woundn't compile.. Would be nice if the macro language had helpers to help generate complex calls like this
<FromGitter> <Blacksmoke16> would have to do like `{% unless ann.args.empty? %} , {{ann.args.splat}} {% end %}, ...`
<FromGitter> <bew> But if you cache the values you double the size of the objects...
<FromGitter> <Blacksmoke16> sacrificing memory for execution time, if you dont cache you do the opposite
<FromGitter> <bew> Hmm let the user decide 😛 by providing a include or class annotation (since you like that!) to cache validation by caching the values
<FromGitter> <Blacksmoke16> probably doable
<FromGitter> <bew> And if he doesn't need caching, no memory waste
<FromGitter> <Blacksmoke16> good call
<FromGitter> <Blacksmoke16> next thing i want to work on is allowing user to define generics
<FromGitter> <bew> Generic asserts? Like what?
<FromGitter> <Blacksmoke16> sec
ma__ has joined #crystal-lang
<FromGitter> <Blacksmoke16> oh yea, i wanted to use the pos args for that
<FromGitter> <Blacksmoke16> for example
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d5b361ebeba830fffc7c288]
<FromGitter> <Blacksmoke16> notice the `(P, M)` generics
<FromGitter> <Blacksmoke16> makes the assertion generic in that can give it any db model to assert against
<FromGitter> <Blacksmoke16> which in this example it would do a db query to make sure some type exists with that ID
<FromGitter> <bew> I'd suggest doing `Assert::RegisterGeneric(...)` or similar, so you can specify the number of generic types vs the arguments if any, and differenciate the 2 calls when needed
<FromGitter> <bew> Pretty cool
<FromGitter> <Blacksmoke16> why would that be required?
<FromGitter> <Blacksmoke16> if you dont add them to the class it wouldnt compile saying expected 1 generic type but got 2
<FromGitter> <Blacksmoke16> or if you dont add it to the property annotation would be same thing, expect opposite
alex`` has quit [Ping timeout: 245 seconds]
<FromGitter> <bew> How do you know in the validation generation if `Type` is a pos arg or a generic arg to
<FromGitter> <Blacksmoke16> i would assume all pos args in the assertion annotations are for generics
<FromGitter> <bew> Ah
alex`` has joined #crystal-lang
<FromGitter> <bew> Please welcome user stupidity, with new errors 👏
<FromGitter> <Blacksmoke16> could easily do compile errors
<FromGitter> <Blacksmoke16> should be pretty clear :P