jhass changed the topic of #crystal-lang to: The Crystal programming language | https://crystal-lang.org | Crystal 0.35.1 | Fund Crystal's development: https://crystal-lang.org/sponsors | GH: https://github.com/crystal-lang/crystal | Docs: https://crystal-lang.org/docs | Gitter: https://gitter.im/crystal-lang/crystal
<raz> yup, it's easy enough anyway
<FromGitter> <Blacksmoke16> mhm
<raz> i feel like that's all stuff that can still be refined/perhaps cleaned up later
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <Blacksmoke16> @rukkiddo get it working with @straight-shoota's suggestion?
<FromGitter> <Blacksmoke16> in other new, writing up the docs for the negotiation component, should have that released soon
* raz cheers
<FromGitter> <Blacksmoke16> while you're here, want your thoughts on how to configure something
<FromGitter> <Blacksmoke16> so tl;dr i have this ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3db584eba353cdff65b17]
<FromGitter> <Blacksmoke16> dont mind too much of it, but the jist is its a listener that sets the format of the request based on content negotiation
<FromGitter> <rmarronnier> Hey all, does anyone of you have experience with the crystal-db logger ? I'm using `DB::Log.level = :debug` and correctly get `▸ Executing query` lines in my terminal... but without the associated SQL query. How can I display it (https://github.com/crystal-lang/crystal-db/blob/master/src/db/statement.cr#L145)?
<FromGitter> <Blacksmoke16> lib im referencing allows you to configure things on a regex based path basis, like ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3dbe12084ee4b786c2171]
<FromGitter> <Blacksmoke16> which seems like it would be a good way to handle this? Also would give a place to set the allowed priorities for each path
<FromGitter> <Blacksmoke16> @rmarronnier maybe open that file in `lib/` and add a `pp` to see what `command` is?
<FromGitter> <Blacksmoke16> also prob going to default that listener to disabled, just so there isnt any sudden change in behavior w/o opting in
<FromGitter> <Blacksmoke16> @rmarronnier also may be possible that the log formatter thats being used isnt rendering context/metadata
<raz> blacksmoke16: yup that rules format looks great. feels like that should go in an annotation like `@ART::Accept(priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false)]`.
<FromGitter> <rmarronnier> > maybe open that file in lib/ and add a pp to see what command is? ⏎ Thanks, I'll try that ⏎ >also may be possible that the log formatter thats being used isnt rendering context/metadata ⏎ Mmm... good point. Thanks for your help :-) [https://gitter.im/crystal-lang/crystal?at=5fe3de99dbb17f28c59832ad]
<FromGitter> <Blacksmoke16> raz: instead of the yaml file like the cors stuff?
<FromGitter> <Blacksmoke16> like what would you apply the annotation to?
<raz> hm, i haven't seen the cors stuff yet. i was thinking like `@[ART::Accept(prio: 'json']; @[ART::Get("/")]; def get_json; ..; end` and then possibly having multiple of them for each desired format. but... i can see how that can get tricky in all sorts of ways. maybe not worth it
<FromGitter> <Blacksmoke16> https://github.com/Blacksmoke16/athena-blog-tutorial/blob/master/athena.yml would prob be a `format` or `content_negotiation` obj under the `routing` key
<FromGitter> <Daniel-Worrall> Can we get a makefile option to build for windows
<raz> ah! hmm yea, that should work, too. tbh i doubt it will see much use anyway. Accept-trickery is just too much of a footgun, i don't remember ever seeing it in the wild on a real API.
<FromGitter> <Blacksmoke16> better than needing separate routes for something tho
<FromGitter> <Blacksmoke16> or like a `/posts` and `posts.html` or whatever
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <Blacksmoke16> but how you figure its a footgun, seems pretty straightforward to me
<raz> that's because you're a framework-dev. ask your average web-dev what they know about the Accept-header ;)
<raz> but that doesn't mean athena shouldn't have the feature. it can def be useful, even tho it's probably relatively rare. the footgun part starts with having endpoints support multiple formats (most people struggle with keeping just one format consistent), logging/debugging opacity (path alone doesn't tel what format was requested/returned) etc.
<FromGitter> <Blacksmoke16> granted idk how often an API needs to return more than one type
<FromGitter> <Blacksmoke16> thats where this implementation comes into play
<FromGitter> <Blacksmoke16> sec
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3e20569ee7f0422bde446]
<FromGitter> <Blacksmoke16> same endpoint, the view obj abstracts the data/status/etc as we talked about. Then its up to the format handlers to actually handle rendering the data in the expected format
<raz> hmm yea, looks like a nice way of doing it for some use-cases. e.g. i could in theory use that for my json:api wrapping. except... in practice i don't ever want to return it in a different format anyway ;)
<raz> but yup, that looks clean enough for cases where it's needed to me
<FromGitter> <Blacksmoke16> main use cases i could see are like maybe json, csv, rss, xml
<FromGitter> <Blacksmoke16> and ofc html
<FromGitter> <Blacksmoke16> how to exactly render those things in that format is ofc up to the dev
<raz> yup
<FromGitter> <Blacksmoke16> a future enhancement could be like versioning
<raz> nope
<FromGitter> <Blacksmoke16> ```Accept: application/vnd.example.v1+json ⏎ Accept: application/vnd.example+json;version=1.0``` [https://gitter.im/crystal-lang/crystal?at=5fe3e385ce40bd3cdbfbd248]
<raz> nope
<FromGitter> <Blacksmoke16> :shrug:
<raz> people have tried that before
<raz> that's why everyone uses /v1/foo or /foo.v1 nowadays ;)
<raz> convincing all your clients, proxies etc. to log enough information just to figure out what version was requested is a nightmare
<raz> debugging is hard enough without that, so the version goes in the path
<FromGitter> <Blacksmoke16> i mean just log the header?
<FromGitter> <Blacksmoke16> not real hard
<raz> um. yup, except nothing does it by default. and many things like CDNs don't even offer it as an option.
<FromGitter> <Blacksmoke16> they all have their pros and cons
<raz> well, it's hard to think of a pro for that particular one ;)
<FromGitter> <Blacksmoke16> he has 2 why he likes the accept header approach
<raz> yup, key phrase `I have the luxury of controlling both the API and the primary consumer of it`
<FromGitter> <Blacksmoke16> right, depends on what exactly you want to get out of it queryparam/custom header seem like the 2 least favorable options
<raz> amusingly custom header is actually the 2nd most popular option after path
<raz> many big apis (e.g. stripe) do that in addition to path-versioning, because the accept-header also has a tendency to get mangled by proxies, can mess with caching, etc.
<FromGitter> <Blacksmoke16> :shrug:
<raz> but anyway, none of that means athena shouldn't have the feature :)
<FromGitter> <Blacksmoke16> saving that part for a future date
<FromGitter> <Blacksmoke16> lib it based things off of doesnt support it so maybe by the time i go to do it they'll have done it already xD
<FromGitter> <Blacksmoke16> lib I
<raz> yeh, it's def a bit on the esoteric/advanced side. but then again, i don't see much else that's still missing from athena :D
<FromGitter> <Blacksmoke16> security stuff
<FromGitter> <Blacksmoke16> and still not 100% sure how i want to handle configuration
<FromGitter> <Blacksmoke16> and the orm...but thats a pita ha
<raz> hmm true, that can't hurt. although most security stuff is only relevant if you want to make it full web-framework. for an api, auth and rate-limiting are pretty much the only two
<FromGitter> <Blacksmoke16> even an api needs to be able to restrict content to those with access
<FromGitter> <Blacksmoke16> i.e. the authorization side of things
<raz> yea ok, but that's a separate framework
<raz> authena
<raz> and it sounds like ormthena is also on your list
<FromGitter> <Blacksmoke16> ha, should be pretty easy on the authorization side of things
<FromGitter> <Blacksmoke16> just needs done, and the configuration thing plays into it
<raz> yeh, i've just rolled my own with clear. but my needs are fairly simple
<FromGitter> <Blacksmoke16> we'll get there
<raz> 💪
<FromGitter> <Blacksmoke16> also not a huge fan of the devise gem
<FromGitter> <Blacksmoke16> er not that one, pundit i think
<FromGitter> <Blacksmoke16> nvm, its actually pretty close to what i was going to go with
postmodern has joined #crystal-lang
<raz> yeh i think cancancan is the latest hot thing
<raz> but there's no one-size-fits-all. i've had my share of devise, warden, sorcery, omniauth and what not
<raz> never made it far beyond the hello-world examples before things got terrible
<FromGitter> <Blacksmoke16> https://symfony.com/doc/current/security/voters.html is what im used to at work
<raz> yup, coming up with a good API is actually not that hard. problem then tends to be performance and how tightly it has to integrate with the ORM
<raz> rails has an edge there in theory because it ships with its own orm. but in practice, the queries generated by those gems tended to be horrifying
<FromGitter> <Blacksmoke16> oh? voter stuff doesnt really interact with it at all
<raz> ah ok, well, i don't know symfony ;)
<FromGitter> <Blacksmoke16> as you pass in the obj you want to validate against
<FromGitter> <Blacksmoke16> oops
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3eb7fde608143153dafb9]
<FromGitter> <Blacksmoke16> so in theory it could be used by any framework
<raz> hmm yea... but that's the easy case
<FromGitter> <Blacksmoke16> whats the hard case?
<FromGitter> <Blacksmoke16> like current user permissions?
<raz> in my experience the one where you go "query this table only for the items that the current user is allowed to see, based on their group memberships/capabilities/subscription status and moon phase"
<FromGitter> <Blacksmoke16> fair point
<FromGitter> <Blacksmoke16> i actually dont know off hand what you can do to handle that
<FromGitter> <Blacksmoke16> ah right
<FromGitter> <Blacksmoke16> https://github.com/Happyr/Doctrine-Specification we use this lib, and then have reusable specs setup so you can do like: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3ec93aa6bb528c36ad458]
<FromGitter> <Blacksmoke16> which can contain all the hacky logic :P
<raz> hehe
<FromGitter> <Blacksmoke16> i really like the concept tho, big fan of that lib
<raz> yea well, on the RDBMS side it lands you in the beautiful world of polymorphic associations (exclusive belongs-to)
<FromGitter> <Blacksmoke16> type safe reusable query building
<FromGitter> <Blacksmoke16> in a non painful way
<FromGitter> <Blacksmoke16> we use a lot of MTI at work
<FromGitter> <Blacksmoke16> STI works well enough if each type shares the majority of the columns
<FromGitter> <Blacksmoke16> otherwise better off with parent table with common stuff and child table for each type's specific stuff
<raz> yup, but for ACLs the above is the way to go. MTI / polymorphism isn't required, but the auth-layer does need to tell the ORM what queries/joins to make.
<raz> otherwise you end up with some "fetch-everything, filter in memory" construct that only works for small datasets
<FromGitter> <Blacksmoke16> yea thats not feasible
<FromGitter> <Blacksmoke16> sounds like a tomorrow problem :P
<raz> yeh, just use clear for the ORM. it's really, really good
<FromGitter> <Blacksmoke16> for an AR style at least 😉
<FromGitter> <Blacksmoke16> was going to go for a more data mapping/repo based approach
<FromGitter> <Blacksmoke16> has some cool benefits, but also cons ofc
<raz> yea, i don't mind AR so much
<raz> my personal fav was crecto
<raz> but that sadly looks unmaintained
<FromGitter> <Blacksmoke16> mhm
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3efb993af5216fc5d2ce4]
<FromGitter> <Blacksmoke16> is tl;dr for what i was picturing
<FromGitter> <Blacksmoke16> main thing i like is the `User` obj is just a class, i.e. it doesnt handle its own persistence
<FromGitter> <Blacksmoke16> so since thats abstracted if you do like ⏎ ⏎ `````` [https://gitter.im/crystal-lang/crystal?at=5fe3f00093af5216fc5d2d7f]
<FromGitter> <Blacksmoke16> ```em.find User, 1 ⏎ em.find User, 1``` [https://gitter.im/crystal-lang/crystal?at=5fe3f009dbb17f28c59859c8]
<FromGitter> <Blacksmoke16> will only make 1 query
<raz> hm yup, looks similar to crecto. i just dunno if it's worth starting yet another ORM. they are pretty hard.
<FromGitter> <Blacksmoke16> suuuuper low priority, i just mess around with it on the side as its pretty neat
<FromGitter> <Blacksmoke16> plus the compiler bugs i ran into dont help ha
<FromGitter> <Blacksmoke16> and yes, it hurts my brain when i come back to it after a while
<FromGitter> <Blacksmoke16> its just the one thing that left in athena land that makes things harder to test
<raz> yea, it's def fun. but i think it's also worth focussing efforts on one de-facto orm (probably clear)
<FromGitter> <Blacksmoke16> clear has the problem that its AR based, which can work in athena land but not as ideally as id like
<FromGitter> <Blacksmoke16> like if you have ⏎ ⏎ ```def users : Array(User)``` [https://gitter.im/crystal-lang/crystal?at=5fe3f0f169ee7f0422be0468]
<FromGitter> <Blacksmoke16> ```def users : Array(User) ⏎ User.all ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5fe3f0fc8bb7347469500e1b]
<FromGitter> <Blacksmoke16> as an endpoint, how do you test that easily?
<FromGitter> <Blacksmoke16> well bad example as you'd just use an integration test in a test env
<raz> yea, that's what i do, i just test the json reply
<raz> since that's the only thing i care about anyway ¯\_(ツ)_/¯
<FromGitter> <Blacksmoke16> one solution i can see is creating a dedicated service to wrap the DB calls, i.e. follow the repository pattern but have the implementation just be AR based
<raz> i dunno. i just have my clear models. and call stuff from the controller handlers.
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3f19e69ee7f0422be0618]
<raz> maybe i'll put some service-classes in between at some point but... why make things complicated ¯\_(ツ)_/¯
<FromGitter> <Blacksmoke16> deff more helpful with a larger app
<FromGitter> <Blacksmoke16> is just a good pattern to follow as it makes `SomeService` trivial to test
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe3f1ff2084ee4b786c54d3]
<FromGitter> <Blacksmoke16> tada, unit test w/o needing db
<raz> yeh, i disagree with that testing style
<raz> i'll never understand why people go to these lengths just to abstract everything away that makes their tests meaningful :P
<FromGitter> <Blacksmoke16> oh? why?
<raz> when testing an API i want to send a request, and verify the reply. if the reply is correct, then the stuff in between probably did the right thing.
<FromGitter> <Blacksmoke16> ofc this is a contrived example, but its easy to see the concept and why it would be helpful
<raz> yea, in some cases stuff like external APIs need to be mocked out, that's the hard part
<FromGitter> <Blacksmoke16> to be clear, integration testing like that is totally the way to go for controllers
<FromGitter> <Blacksmoke16> but unit tests are also good to have
<FromGitter> <Blacksmoke16> in which case this pattern allows more easily getting the service into each test state
<FromGitter> <Blacksmoke16> esp for things that your app does that *arent* part of the request/response flow
<raz> integration tests cover these too, or they are incomplete
<raz> make request, check that email is sent if it should, check that db record was created, check that queue job executes, verify reply.
<raz> i.e. verify all effects that the request should have
<FromGitter> <Blacksmoke16> im not doubting the usefulness of integration tests, they're deff the way to go most of the time
<FromGitter> <Blacksmoke16> i just think you should not forsake unit tests entirely for them
<FromGitter> <Blacksmoke16> like following along with the service style approach from above, if you have good test coverage on that service it can be assumed wherever it's used, it'll function properly
<FromGitter> <Blacksmoke16> which might not all be covered in integration tests, depending on how the caller uses it
<FromGitter> <Blacksmoke16> granted assuming you write another integration test for something else that uses it, that could find the bug as wel
<FromGitter> <Blacksmoke16> with the downside that it may be harder to find whats actually failing :shrug:
<raz> yeh, if it's a good unit test, i'll take it, cause why not. i just way too often see people obsess over testing that a method really gets called when they call it.
<FromGitter> <Blacksmoke16> i think its deff possible to write *too* many tests
<FromGitter> <Blacksmoke16> i.e. unit testing something for sake of unit testing it
<FromGitter> <Blacksmoke16> which is a smell in of itself
<raz> yup yup
<FromGitter> <Blacksmoke16> https://kentcdodds.com/blog/write-tests like this guy puts it ha
<FromGitter> <Blacksmoke16> i personally like to see the all the green `.` tho
<raz> yap, just skimming it i can agree with many of these words :)
<FromGitter> <Blacksmoke16> ```1000.times do ⏎ it { 1.should eq 1 } ⏎ end``` ⏎ ⏎ 😆 [https://gitter.im/crystal-lang/crystal?at=5fe3f60569ee7f0422be0f44]
<raz> switch the dots to doc mode and make sure your suite tells a proper story
<raz> that's even more satisfying ;)
<raz> tho ofc only applicable when there's an actual story to tell, like in a business app. for a framework like athena it would be a rather abstract and technical tale ;)
<raz> "the request successfully passed handler
<raz> A, B, C, D, E ...."
<raz> 😬
<FromGitter> <Blacksmoke16> @AlexCouch fwiw this might be helpful based on the example from your example :P https://crystal-lang.org/api/master/Enumerable.html#compact_map(&)-instance-method
_whitelogger has joined #crystal-lang
f1reflyylmao has joined #crystal-lang
f1refly has quit [Ping timeout: 260 seconds]
avane has quit [Quit: ZNC - https://znc.in]
avane has joined #crystal-lang
hpyc9 has quit [Ping timeout: 260 seconds]
f1reflyylmao has quit [Read error: Connection reset by peer]
hpyc9 has joined #crystal-lang
f1refly has joined #crystal-lang
r0bby has quit [Ping timeout: 260 seconds]
r0bby has joined #crystal-lang
_whitelogger has joined #crystal-lang
bazaar has quit [Ping timeout: 240 seconds]
bazaar has joined #crystal-lang
r0bby has quit [Read error: Connection reset by peer]
r0bby has joined #crystal-lang
<FromGitter> <watzon> How would I go about figuring out if the current system is 32 or 64 bit?
<FromGitter> <watzon> I feel like there's a flag, I just don't know it
postmodern has quit [Quit: Leaving]
r0bby has quit [Read error: Connection reset by peer]
r0bby has joined #crystal-lang
_ht has joined #crystal-lang
<FromGitter> <naqvis> `flag?(:i386)` `flag?(:x86_64)`
_whitelogger has joined #crystal-lang
<FromGitter> <asterite> There are the more precise bits32 and bits64 flags
<FromGitter> <watzon> Oh nice, even better. Another question. I'm trying to use `sizeof` in a macro to check the cumulative size of the generic splat arguments, but it won't work because `sizeof` only works on constants. Any ideas? This is what I'm trying now: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe463b7de608143153ebb0e]
<FromGitter> <watzon> Something like this works, but it seems hacky `{{ @type.type_vars[0].type_vars.map { |v| "sizeof(#{v})".id } }}.sum`
<FromGitter> <naqvis> how about `instance_sizeof` ?
<FromGitter> <watzon> Oh I didn't know that was a thing
<FromGitter> <naqvis> https://crystal-lang.org/api/0.35.1/toplevel.html#instance_sizeof(type:Class):Int32-class-method
<FromGitter> <watzon> Ahh not what I was hoping for. I need the size of the type, not the size of the instance
<FromGitter> <watzon> `instance_sizeof` still requires a type definition as well
<FromGitter> <naqvis> | Returns the instance size of the given class as number of bytes. ⏎ | See sizeof for determining the size of value types.
<FromGitter> <bararchy> Do we have anything like IO.select(socket1, socket2) to get an array of read to read from sockets?
<hightower2> When using -Dpreview_mt, does one need to start at least 1 worker per CPU core to have fibers be on multiple cores, or not?
<hightower2> (by worker I mean Thread)
<FromGitter> <naqvis> no you don't. Scheduler takes care of that
<FromGitter> <naqvis> though you can ask the scheduler to run fibers in same or different(default option) threads
<hightower2> right, I referred to the forum post you linked recently, thanks
<hightower2> On a different topic, how about this idea -- I often change shard.yml to point to my local versions of dependencies. But then I need to revert it back to official/internet locations before committing to git. Can we make crystal search for e.g. shard.yml.local first? This would make this possible without committing the .local file to git.
<raz> recently google sends me to the ancient times again...
sorcus has quit [Read error: Connection reset by peer]
<oprypin> hightower2, shards literally already has exactly that feature
<hightower2> very good :-) thanks
<Andriamanitra> maybe there should be a warning and a link to up-to-date docs when you land on old version from google or similar
<oprypin> there should be a lot of things but frankly the only person who can do it is stalling it
<oprypin> raz, hey at least you can enjoy the nicer fonts from ancient times xD
<straight-shoota> hightower2, it's shard.override.yml and should already work with shards 0.12.0
hightower2 has quit [Ping timeout: 256 seconds]
sorcus has joined #crystal-lang
<raz> oprypin: i'm trying to take it with humor, but quietly wish someone would just delete everything <0.35.1 from the webserver :p
<straight-shoota> it doesn't need to be deleted, just get a <link rel="canonical">
<straight-shoota> ... and a banner that says the version is outdated
<raz> i dunno, i saw a github ticket about it once, but seems like it must be hard problem since it's still not resolved ;)
<straight-shoota> yeah, it must be really hard *shrug*
<raz> ohhh, i should have done this earlier. chrome custom search engine, keyword cr, url https://www.google.com/search?q=site%3Ahttps%3A%2F%2Fcrystal-lang.org%2Fapi%2F0.35.1+%s
<straight-shoota> use latest instead of 0.35.1 and you don't need to update it
<oprypin> straight-shoota, yea except it doesnt work; there are no pages indexed as url "latest"
woodruffw has quit [Ping timeout: 272 seconds]
ua_ has quit [Ping timeout: 264 seconds]
woodruffw has joined #crystal-lang
ua_ has joined #crystal-lang
woodruffw has quit [Ping timeout: 260 seconds]
woodruffw has joined #crystal-lang
<straight-shoota> works for me
woodruffw has quit [Ping timeout: 260 seconds]
<FromGitter> <Blacksmoke16> https://athena-framework.github.io/negotiation/Athena/Negotiation.html ⏎ ⏎ Enables implementing content negotiation into any project. Is dependency free and framework agnostic.
<FromGitter> <Blacksmoke16> Release `v0.1.0`
<oprypin> straight-shoota, 9 results (for the whole sub-site) at your url 🤔
woodruffw has joined #crystal-lang
hightower2 has joined #crystal-lang
<hightower2> Hey is this a bug https://carc.in/#/r/a5yt ?
<hightower2> Doing @x, @y = 1, 2 in the shown case fails, while doing it separately in 2 lines works
<oprypin> hightower2, from the code i see that you probably realize that you should just delete that assignment and that's the right way to do it. but just saying.
<hightower2> Yes but this is because I want the function to set instance vars
<oprypin> you're setting them inside `initialize`
<hightower2> I assign inside initialize() just to get around the issue of indirect initialization not being supported
<hightower2> (and I don't want to use getter!)
<oprypin> i dont quite understand, is there anything preventing you from having such a function without the ivar assignment
<hightower2> yes, I want the function to set those variables. If I do it without ivar assignment, then I need another function which will do the assignment
<hightower2> the point is... this function will be called many times to (re)set the values, not just once in initialize
<hightower2> and I want to just call find_out() every time, and not do: @x, @y = find_out()
<oprypin> well i think this is still the best bet https://carc.in/#/r/a5yv
<oprypin> regarding your question if it's a bug, yea it's an interesting one
<hightower2> I'll file a bug report
<hightower2> thanks for the discussion, as always
<oprypin> if there was ever a quiz on compiler knowledge, explaining it should be in it
<oprypin> straight-shoota, in the array assignemt pull request you show that you know what code something expands to. is there any easy way to print that?
<FromGitter> <christopherzimmerman> Is LLVM8 still the default for Crystal?
<straight-shoota> oprypin, oh right. I even tried it with a type name and it was in the results, so I didn't look further :D
<straight-shoota> I don't think there is a direct way to print the "final" code. Those transformations happen in different semantic visitors like literal_expander and normalizer
<straight-shoota> You can look at the implementations or specs
<straight-shoota> IIRC there was some idea to add an --emit option that prints the final code right before the codegen phase
<straight-shoota> that shouldn't be hard to to, actually
<hightower2> Regarding another way of getting around indirect initialization not supported, I thought of this: https://carc.in/#/r/a5zg , but seems testing the var with || is prevented. Would anyone know if this is a hard limitation (one basically identical to having indirect initialization), or some provisions could be made for this to work?
<straight-shoota> @christopherzimmerman I think LLVM 10 should be considered standard, but a lot of older versions are supported
<FromGitter> <christopherzimmerman> Oh nice, didn't realize 10 was supported, should https://crystal-lang.org/install/from_sources/ be updated then?
woodruffw has quit [Ping timeout: 265 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 246 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 260 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 256 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 256 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 265 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 240 seconds]
woodruffw has joined #crystal-lang
woodruffw has quit [Ping timeout: 246 seconds]
woodruffw has joined #crystal-lang
<hightower2> Is there a faster way to write multiple args to an IO other than args.each { |a| io << a } ?
<FromGitter> <Blacksmoke16> did you try `io << args`?
<hightower2> if I do that it prints me e.g. "{1,2,3,4}" (the tuple that was passed as *args to the method)
<FromGitter> <Blacksmoke16> what about `args.inspect io`
<FromGitter> <Blacksmoke16> otherwise what you have is prob fine
<hightower2> {1, 2, 3, 4}
<hightower2> ok, sticking with the each method, thanks
ua_ has quit [Ping timeout: 246 seconds]
postmodern has joined #crystal-lang
ua_ has joined #crystal-lang
woodruffw has quit [Ping timeout: 256 seconds]
<FromGitter> <watzon> Who was it the other day that told me about their project for packing and unpacking bytes into structs?
woodruffw has joined #crystal-lang
<FromGitter> <Blacksmoke16> @j8r
<FromGitter> <watzon> Ahh yeah
<FromGitter> <watzon> I guess I was remembering crystalizer as being something it's not. I'm looking for a more user friendly way to pack and unpack binary data.
<FromGitter> <watzon> I'm working on something right now that's kind of like Python's struct, but more type friendly
woodruffw has quit [Ping timeout: 246 seconds]
hightower2 has quit [Ping timeout: 240 seconds]
<FromGitter> <watzon> Is there something like this that already exists? ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5fe4e4e322f12e449b0dde7f]
<FromGitter> <watzon> I know that ByteFormat exists, it's just not a very convenient API. The goal would be to wrap it in something a little more user friendly.
<FromGitter> <Blacksmoke16> ah
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <watzon> I'm working with RPC packets, each of which (and there's 1000s) needs to be able to be packed and unpacked from a byte slice (which is what gets sent over the network). The library I'm basing mine off of is written in Python, so they use a ton of `struct.pack` and `struct.unpack`. I want to do something a bit more Crystal-esque though, so I'm thinking when I generate the types I can just have each field be
<FromGitter> ... annotated and have a different library do all the byte magic.
<FromGitter> <asterite> Chris: https://shardbox.org/shards/bindata
<FromGitter> <asterite> It's in the spider gazelle repo so it must be excellent
<FromGitter> <watzon> Aha! I knew I'd seen something like this before
<raz> namedtuples as return values seem to prone to cause seg faults 😓
<raz> can't really condense it down to a small sample, but seems like something gets confused when two methods on a class return tuples that differ only in a value-type (e.g. `def a : { foo: ClassA }` and `def b : { foo: classB }`)
<FromGitter> <Blacksmoke16> Use structs
<raz> when i change the return-type on one of them to anything else, the segfault goes away
<raz> yea that's what i'm doing now. was a bit wary of those tuples anyway, just surprised they crash so hard
<raz> anyway, for the gallery http://ix.io/2Jqq/
woodruffw has joined #crystal-lang
ua_ has quit [Ping timeout: 256 seconds]
<FromGitter> <rukkiddo> > mom, it was because gnupg2 was missing ⏎ hey @straight-shoota this was the answer thanks & @Blacksmoke16 thanks for following the issue with me, now it works fine
ua_ has joined #crystal-lang
<oprypin> raz, tried that on crystal master?
<oprypin> indeed there's no idiomatic use of namedtuples as return types, ever, but yea...
<FromGitter> <Blacksmoke16> i did notice that https://dist.crystal-lang.org/apt/setup.sh doesnt have `sudo` on the key add part
<oprypin> Blacksmoke16, all 3 of the lines would need sudo . it counts on running as sudo itself
<FromGitter> <Blacksmoke16> so that prob needs updated then
<oprypin> what why
<FromGitter> <rukkiddo> it is better to leave it like this
<FromGitter> <rukkiddo> imo
<FromGitter> <Blacksmoke16> i guess what im getting at is if you do like `sudo curl ... | bash` does the script fetched via curl inherit the sudo?
<FromGitter> <rukkiddo> I run that on docker, it didnt require sudo for me, actually anything I run with sudo has problem in the dockerfile
<FromGitter> <Blacksmoke16> in docker you're most likely already root
<FromGitter> <Blacksmoke16> but at that point why not just use the crystal docker images versus installing it like that/
<oprypin> Blacksmoke16, in docker sudo can just break
<oprypin> Blacksmoke16, it doesnt "inherit", those are 2 separate processes, just happen to share stdio. but that's why you run `curl ... | sudo bash`
<FromGitter> <Blacksmoke16> ah yea, good point
<FromGitter> <watzon> Sometimes I wish we had a Hash initializer that works like python's `defaultdict`. It's possible to intiaalize the hash with a block to give it the same behavior, but it's not very succinct, especially when you're doing it multiple times.
<FromGitter> <watzon> Appendix A:
<FromGitter> <Blacksmoke16> im also a fan of the idea if an overload takes a block it should also take a proc
_ht has quit [Remote host closed the connection]
<FromGitter> <Blacksmoke16> but fwiw cant you do like `namespace_functions = namespace_types = namespace_patched = Hash(String, ...`?
woodruffw has quit [Ping timeout: 240 seconds]
r0bby has quit [Ping timeout: 268 seconds]
r0bby has joined #crystal-lang
<FromGitter> <watzon> Oh that's true, good idea
hightower2 has joined #crystal-lang
<FromGitter> <watzon> I think it would be nice to have an initializer for Hash like `Hash(String, Array(TLObject)).default` where it will try to just call `.new` on the value type if the key doesn't exist, but I don't envision something like that getting merged.
<hightower2> Hey folks does anyone know what's the progress or status re. missing support for indirect initialization? At this point I would list it the #1 issue that's bothering me
<oprypin> what's indirect iniaizliaztion
<hightower2> that thing where you can't initialize a non-null variable from a method other than initialize()
<hightower2> like, can't say "@a : Int32" and then call set_a() from initialize(), but need to do "@a = set_a()"
<oprypin> hightower2, it's declared working as intended
<oprypin> show your real use case and let's see what you could do there
<hightower2> I mean this https://carc.in/#/r/a615
<hightower2> The solutions to get around this is to either say "@a = set_a", or to define "getter! a : Int32", both of which have consequences for the rest of the code
<oprypin> hightower2, no show your real use case
<hightower2> Any method which is intended to set values of ivars, and which I don't want to effectively have coded twice (one time in the method, and one time in the initialize() to get around this issue)
<FromGitter> <Blacksmoke16> have you considered just not doing that
<oprypin> [16:46:36] <oprypin> well i think this is still the best bet https://carc.in/#/r/a5yv
<raz> oprypin: re: tried that on master - nope, i'm on 0.35.1 only. not too worried since it was reliably reproducible (most likely something someone already has their eyes on - and i try to avoid NamedTuples anyway, so not a big loss there for me)
<FromGitter> <Blacksmoke16> `Error: no overload matches 'Regex.new' with types YAML::ParseContext, YAML::Nodes::Node+` rip
<raz> blacksmoke16: can i configure the cors stuff without a config file somehow? config files are the devil
<FromGitter> <Blacksmoke16> umm
<FromGitter> <Blacksmoke16> can overload `def Athena::Config.load : ACF::Base`
<FromGitter> <Blacksmoke16> and things should just work
<raz> and feed it yaml?
<FromGitter> <Blacksmoke16> sure
<FromGitter> <Blacksmoke16> i dont think the structs have initializers so that would prob work :shrug:
<FromGitter> <Blacksmoke16> still not 100% sure how i want configuration to be longer term
<raz> env vars. env vars only.
<raz> where is this Config.load even defined hmm
<FromGitter> <Blacksmoke16> i like env vars, but you're kinda limited with them
<FromGitter> <Blacksmoke16> i.e. like would be kinda hard to configure cors with them..
<FromGitter> <Blacksmoke16> its a part of the config component
<FromGitter> <mattrberry> Cleanest way to add tuples component-wise? I’d say zip + map, but zip returns an array. Could build a tuple back out of that, but that isn’t super nice. Any nicer ways to do it in a single line?
<FromGitter> <Blacksmoke16> https://crystal-lang.org/api/master/Tuple.html#from(array:Array):self-class-method
<oprypin> mattrberry, cleanest way is to not automate that
<oprypin> e.g. `{a.x + b.x, a.y + b.y, a.z + b.z}`
<FromGitter> <Blacksmoke16> they type of each item have to be known at compile time, so you cant just dynamically turn an arbitrary array into one
<FromGitter> <Blacksmoke16> the type of each item has*
<FromGitter> <mattrberry> Yeah that was my thought too :/ Oh well
<FromGitter> <watzon> Any idea what might be the most succinct way to do a `String#join` with a prefix for the last item? I want to join items and have the last one have "and " before it.
<oprypin> oh..
<FromGitter> <Blacksmoke16> prob replicate what join does then add something like `if idx == collection.size -1`
<FromGitter> <watzon> So far I have `names = params.join(", ") { |p| p == params.last ? "and " + p :cp }`, but idk if there's a better way
<oprypin> watzon, wait this one does ", and ", not "and "
<oprypin> if that's fine then this is the way
<FromGitter> <watzon> I was today years old when I learned that `join` takes a block
<FromGitter> <watzon> Yeah that's intended. I just want the oxford comma with an "and"
<FromGitter> <watzon> In this case I shouldn't have any repeated items, so checking the value against the list should be fine. This wouldn't work well if items in the list repeat, but then it probably wouldn't make as much sense to have an "and" anyway.
<hightower2> nice hint about join + block
<oprypin> watzon, hmmm could do something like `if (i += 1) == params.size`
<FromGitter> <watzon> It would be nice if the block had an index passed to it, but that's not a bad idea
<FromGitter> <watzon> I'm doing some codegen right now. It's crazy to see a .tl file go in, and hundreds of classes come out.
<FromGitter> <Blacksmoke16> could do something like
<FromGitter> <Blacksmoke16> ```idx = 0 ⏎ names = params.join(", ") { p| "some_str".tap { idx += 1 } }``` [https://gitter.im/crystal-lang/crystal?at=5fe5242dce40bd3cdbfeb95b]
<FromGitter> <Blacksmoke16> think that should work
<raz> Blacksmoke16: http://ix.io/2Jrx/ 🎁
<raz> may still want to robustify it a bit and i dunno how many of your abstractions it violates, but it does the job for me ;)
<FromGitter> <Blacksmoke16> Nice one, I'll check it out
<raz> ah yea, line 17 needs a ? at the end