ChanServ changed the topic of #crystal-lang to: The Crystal programming language | | Fund Crystal's development: | GH: | Docs: | Gitter:
lanodan has quit [Quit: WeeChat 3.4.1]
lanodan has joined #crystal-lang
notzmv has joined #crystal-lang
jmd_ has quit [Ping timeout: 260 seconds]
ur5us_ has joined #crystal-lang
nq has quit [Quit: Leaving]
vegai has joined #crystal-lang
<vegai> hey, I thought about trying the interpreter on 1.4.0
<vegai> what would be the cleanest way to get the linking work when installing to /usr/local ?
<vegai> my librt is in /usr/lib, but seems like the search path doesn't include that
vegai has quit [Quit: to matrix]
<FromGitter> <> oh wait, crystal is looking it from a wrong place anyway
<FromGitter> <> cannot find -lrt (/usr/local/bin/../lib/crystal/ cannot open shared object file: No such file or directory)
<FromGitter> <> well, two symlinks later ( also) and the interpreter works
ur5us_ has quit [Quit: Leaving]
ur5us has joined #crystal-lang
ur5us has quit [Ping timeout: 268 seconds]
jhass has quit [Ping timeout: 250 seconds]
straight-shoota has quit [Ping timeout: 272 seconds]
DeBot has quit [Ping timeout: 240 seconds]
DeBot_ has joined #crystal-lang
jhass has joined #crystal-lang
straight-shoota has joined #crystal-lang
<FromGitter> <> is there a more efficient way to convert a `Hash` or `NamedTuple` to `JSON::Any` than serializing it to json and parsing it back?
<FromGitter> <>
<FromGitter> <> You'll have to iterate over and create a JSON::Any for the value
<FromGitter> <> BTW Crystalizer does it out-of-the-box
<FromGitter> <> hm hm
<FromGitter> <>
<FromGitter> <> merci!
<FromGitter> <> Hum no Crystalizer doesn't have it, but it can convert Anys to one another
<FromGitter> <> All are the same base module, so
<FromGitter> <> One can convert a JSON::Any to yaml and vice-versa at no additional cost
<FromGitter> <> moe ( why do you need to do that though?
sorcus has quit [Quit: WeeChat 3.5]
<FromGitter> <> just a helper class where the user should be able to pass in an arbitrary hash or chunk of json: ` 123, code: "foo", meta: { foo: "bar" } )` (some fields like status & code are fixed, but `meta` can take any json value)
<FromGitter> <> i think your snippet might work, gonna try it out :)
<FromGitter> <> It has to be enhanced, convertings integer and floats for instance
<FromGitter> <> yeh, i've stashed it onto the "fix later" pile. for now json ser+deser works, it's just ugly
<FromGitter> <Blacksmoke16> Why do you need to convert it to json any first?
<FromGitter> <Blacksmoke16> To add the status and code fields?
<FromGitter> <> cause i need to store it in an ivar on the other side, later to be json serialized
<FromGitter> <> slightly simplified:
<FromGitter> <> could perhaps make it a generic in this case, but well, other fish to fry atm :D
<FromGitter> <> Also keep in mind could want a XML or even GraphQL or GRPC API 😉
<FromGitter> <Blacksmoke16> could also just do like `@data = { status: status, code: code, meta: meta }.to_json` and call it a day :P
<FromGitter> <> yeh, maybe for simpler cases. not for my 3 layers of macros here :P
<FromGitter> <Blacksmoke16> :S fair enough
<FromGitter> <> @Blacksmoke16: 😏
<FromGitter> <Blacksmoke16> isnt that just essentially the `record` macro?
<FromGitter> <Blacksmoke16> but for a class
<FromGitter> <> close, yes. but this one takes a NamedTuple. which allows passing it around more easily. which i needed for my crazy DSL
<FromGitter> <> it can do this now: - with auto-swagger docs, validation, content-negotiation etc.
<FromGitter> <Blacksmoke16> Pretty slick! I see you didn't switch your router yet tho 😛
<FromGitter> <> I like it
<FromGitter> <> haha. i actually looked at athena router, might still swap it out. just too many other things to still patch up, that comes last.
<FromGitter> <> I don't know if you've done it, I find sleeker internally if exceptions are not used for 4xx/5xx responses
<FromGitter> <> If find this not very good
<FromGitter> <Blacksmoke16> Haha sounds good 👍
<FromGitter> <> What compile-time guarantees does your framework provides?
<FromGitter> <Blacksmoke16> Exceptions just work so good for error handling like that, I'd think not using them would make things much more complex
<FromGitter> <> yup, responses incl. errors are pre-declared. but exceptions are also properly rendered (can declare are renderer for specific Exception classes, such as ORM errors - otherwise the standard Exception-renderer takes them). this should make it easy to deal with ORMs - no need to catch things like validation errors, just have a renderer for them.
<FromGitter> <> i learned pre-declaring them is pretty much inevitable to generate those docs (as there's no way to discover return-types in crystal unless they are explicitly declared - i think i had asked about that in here the other day)
<FromGitter> <> Exceptions are not compile-time safe, and cannot be automatically showed in swagger docs :/
<FromGitter> <> If an endpoint use return types, like Success | Error, then the swagger docs generator can use this automatically
<FromGitter> <> moe ( ha nice!
<FromGitter> <> A bit like what's I did with my framework too
<FromGitter> <> yap, that's totally right. the way i've solved it (for now) is that exception-renderers automatically add to the Swagger-docs for *all* endpoints. since they can in principle bubble up from anywhere. but not happy with that, yet. if there's a renderer for "Orm::Error" then i don't really want that in the docs for endpoints that don't even use the orm.
<FromGitter> <> In case you'd like some ideas:
<FromGitter> <> guess i'll make a macro to opt-in/opt-out. basically hitting the limit of what can be discovered in crystal there (couldn't find a way to discover any info about exceptions in macro-space)
<FromGitter> <> yea i've looked at that, really cool! :) i just could never figure out the status of grip vs gripen, and it seemed sadly not very maintained
<FromGitter> <> There are separate
<FromGitter> <> @grkek and me thought of having gripen as the grip v2. But at the end, lack of interest to most so didn't materialized
<FromGitter> <> At the end you can see as an experiment. No issues, nothing to do haha 😆
<FromGitter> <> Even Grip is not that used much 🤷
<FromGitter> <> i did use it for a while! but then i keep derailing into building my own frameworks lol
<FromGitter> <> i also started with icyleaf for swagger, but turned out too rigid for me, and also missed some stuff
<FromGitter> <> so now i'm just using the amazing AnyHash and merge to it from all over the places:
<FromGitter> <Blacksmoke16> sure but isnt not using them much more complex just to get swagger docs?
<FromGitter> <Blacksmoke16> related:
<FromGitter> <Blacksmoke16> > guess i'll make a macro to opt-in/opt-out. basically hitting the limit of what can be discovered in crystal there (couldn't find a way to discover any info about exceptions in macro-space) ⏎ ⏎ related:
<FromGitter> <> this gives me hope:
<FromGitter> <Blacksmoke16> if it goes the annotation route, could deff access that in a macro, not so much if its in a comment
<FromGitter> <> yeh, i just want `Def.exceptions` without having to manually declare them (how am i supposed to know what can bubble up from inside the guts of stdlib, that would probably be a dozen lines on every method ;))
<FromGitter> <> but it's probably more a crystal 3.0 type of thing
<FromGitter> <Blacksmoke16> indeed
<FromGitter> <Blacksmoke16> even if thats a thing, prob easier to manually do it anyway
<FromGitter> <Blacksmoke16> because, to your point, are prob going to be a lot of random ones that *could* happen, but in reality wont
jmdaemon has joined #crystal-lang
<FromGitter> <> well, you'd only declare renderers for the ones you care about (like `Orm::ValidationError`). ⏎ then the framework would add their docs only to endpoints that actually raise them. ⏎ ⏎ the rest flows into `Exception` renderer (http 500). the docs for which also get added to all endpoints (because `Exception` can be raised from anywhere). [
<FromGitter> ... rystal-lang/crystal?at=625326868db2b95f0aacf27e]
<FromGitter> <Blacksmoke16> ahh okay, yea that makes more sense
<FromGitter> <> yeh, wishful thinking for now. but anyway, already quite happy with what i got so far. keeping the swagger those swagger comment-annotations in sync with what the handler actually does has been a pain point in pretty much every project here. having 99% of it fall out automatically will already make life easier.
<FromGitter> <Blacksmoke16> how are you handling validations?
taupiqueur has joined #crystal-lang
<FromGitter> <> nothing too fancy, just have a param class for each type:
<FromGitter> <> the args in `initialize` automatically become available in the macro, so each type can have different ones
<FromGitter> <Blacksmoke16> 👍 gotcha
f1refly has joined #crystal-lang
<FromGitter> <> <- here's the fancy part of that. macro mania. ⏎ (renderer can be ignored, that's still from the early days. gotta change it to just re-raise as `JsonApi::Error` sometime - no need to duplicate the response-formatting in there)
brw has quit [Quit: The Lounge -]
brw has joined #crystal-lang
* FromGitter * Blacksmoke16 wants his macro defs
<FromGitter> <> can't spill all the beans yet :p
<FromGitter> <Blacksmoke16> dont forget about testing ^
<FromGitter> <Blacksmoke16> having some good ways provided by the framework to do that can be helpful
f1refly has quit [Read error: Connection reset by peer]
taupiqueur has quit [Quit: taupiqueur]
f1refly has joined #crystal-lang
ur5us has joined #crystal-lang
<FromGitter> <> yup, my religion is end-to-end testing, so i got spec helpers to simulate requests and this little db doodad in
<FromGitter> <Blacksmoke16> 👍 nice
<FromGitter> <Blacksmoke16> Tho i mean exposing those helpers to let users of the framework use them too
<FromGitter> <> yea they can, i mean, it's all just in the spec_helper :D
<FromGitter> <>
<FromGitter> <> so just require lux/spec_helper and it'll be there. athena prob has something similar
<FromGitter> <> admittedly mine has no fancy DI/mocking or anything like that. maybe later. tho tbh, i've never found that very useful in the past. ultimately i just wanna know that request A gives response B. what happens in between... well, if the response is correct, then it's probably correct ;)
<FromGitter> <Blacksmoke16> I never considered just requiring another libs spec helper
<FromGitter> <> well, strictly speaking it's the spec_helper_helper ;)
<FromGitter> <Blacksmoke16> Always assumed that was a bad idea and exposed a dedicated file
<FromGitter> <Blacksmoke16> Ahh gotcha
<FromGitter> <> yea, it's probably not "clean" to inject top-level helpers like that. but it works and not sure what a cleaner way would really look like (or gain).
<FromGitter> <> You could make it a module I guess
<FromGitter> <> With `def self.mock_request`. Up to the user to include it where needed
<FromGitter> <> Or call the method directly from the module
<FromGitter> <> yea, but that's prob part of the things i learned while dabbling with this. ⏎ if you want to be truly dynamic then "clean" doesn't go far. it's macros and generating classes all the way. initially i tried very hard to enable "" and having multiple instances in peaceful coexistence. but then realistically, who really need multiple server instances in their app... things became way easier after
<FromGitter> ... accepting it has to be a "there can be only one" kemal-style affair
<FromGitter> <> so in the main app all the generated stuff is tucked away under the Lux namespace, to keep a bit of isolation at least. but in the spec-helper... i guess could namespace that as well. but if you require that then you're probably testing a lux app. so why type four extra letters instead of just get("/foo") 🤷‍♂️
<FromGitter> <> the other thing i learned: basically every macro error is fixed by adding a backslash before {% :P
<FromGitter> <Blacksmoke16> could still do that by just having two separate entrypoints that require common code and only the routes each server should have
<FromGitter> <Blacksmoke16> do you know about `{{debug}}`?
<FromGitter> <> ha, yea, it's fun to get these comments from other framework devs. :D of course you'd spot that right away and yea that's exactly my thinking. i can have multiple listeners already, will prob add optional scoping of endpoints to listeners sometime. so then multiple "instances" will be possible, just without it being an actual class instance.
<FromGitter> <> yea {{debug}} is mighty helpful, although i've needed it surprisingly rarely. the compiler errors have gotten really good, most of the time it dumps the relevant part by itself
<FromGitter> <Blacksmoke16> exactly yea. Its mostly under the "worry about it when there's an actual use case for it" bucket
ur5us has quit [Ping timeout: 268 seconds]