deavmi has quit [Read error: Connection reset by peer]
deavmi has joined #crystal-lang
blueberrypie has left #crystal-lang ["leaving"]
<FromGitter>
<Blacksmoke16> i could believe it
hightower3 has quit [Ping timeout: 246 seconds]
<companion_cube>
mm probably false alarm
<FromGitter>
<Blacksmoke16> π
<FromGitter>
<cfishbein> Hi all. Love the language! Question regarding `Socket::IPAddress`: it seems to require defining a port. This feels a bit wonky when dealing with IP Addresses that only meant to identify another user. I will typically just give a `0`. Is this intentional or there just isn't enough usage for this object without a defined port?
<FromGitter>
<cfishbein> Just plain user identification. A list of IP addresses on my home network for example.
Nekka has joined #crystal-lang
<FromGitter>
<Blacksmoke16> could just store them as strings then?
<FromGitter>
<cfishbein> I could, but then I lose a lot of nice validation or address manipulation (to which I would just store them as UInt32's). Not a huge deal and I have plenty of ways to achieve what I need without. Just thought I'd point it out as an oddity since when I think IP Address, I don't typically think of a port being required.
<FromGitter>
<Blacksmoke16> Could make an issue about it, I don't recall seeing anything about it
<FromGitter>
<cfishbein> I'll mull it over. I'm still not sure if this is just preference or there is really any value in making this kind of change to the standard lib. Thanks for your input!
<FromGitter>
<Blacksmoke16> Np, could start off with a forum post as well
<FromGitter>
<sam0x17> I also have found it annoying that port is aggressively a part of the ip struct
_whitelogger has joined #crystal-lang
_whitelogger has joined #crystal-lang
rocx has quit [Ping timeout: 260 seconds]
lunarkitty has quit [Ping timeout: 260 seconds]
lunarkitty has joined #crystal-lang
zorp_ has quit [Ping timeout: 265 seconds]
_ht has joined #crystal-lang
_whitelogger has joined #crystal-lang
<raz>
blacksmoke16: back! :)
<raz>
cfishbein: agree, `Socket::IPAddress` seems to be a bit of a misnomer as it really identifies a socket (which needs ip + port). would suggest for crystal to rename it to `Socket::Address` and invent a new top-level `IPAddress`. these would then be equivalent to java's `InetSocketAddress` (ip+port) vs `InetAddress` (only ip).
tdc has joined #crystal-lang
_ht has quit [Remote host closed the connection]
hightower2 has joined #crystal-lang
<hightower2>
Hey is there something like batch-loader for Crystal?
<raz>
oprypin: it's sneaky, only appears when you click on a thread
<oprypin>
ah it shows misaligned like that briefly and then disappears
<oprypin>
must be Discourse changed under our feet
<raz>
well, probably not the highest priority thing. :p
<raz>
it just hurts my teeth :E
hsh has quit [Quit: Connection closed for inactivity]
mntmn_ has joined #crystal-lang
<mntmn_>
hi, we're making an aarch64 based laptop and i wanted to try crystal on it. where can i find an aarch64 binary? the build process already seems to require a crystal binary?
<FromGitter>
<Blacksmoke16> where `configuration` would hold metadata associated with the converter, like name of the argument it applies to, and/or any user supplied stuff. `@[ART::ParamConverter("num", converter: MultiplyConverter, by: 3)]`
<FromGitter>
<Blacksmoke16> i.e. `value * configuration.options[:by]`
<FromGitter>
<Blacksmoke16> or something like that
<raz>
hum. not sure i fully understand, but that annotations syntax looks very good to me.
<raz>
as a framework-user that's exactly what i want to write.
<FromGitter>
<Blacksmoke16> essentially `request.attributes` stores arbitrary data, like query/path params, plus whatever else the user stored in it. So param converters now would just be mutating those values in attributes
<raz>
or more precisely, i want to write: @[ART::Param("num", parse_as: Integer, addl_options: "could go here")]`
<FromGitter>
<Blacksmoke16> well assuming the route is like `/multiply/:num` that would already happen
<FromGitter>
<Blacksmoke16> would be supplied as `Int32` or whatever Int restriction the argument has
<raz>
ah yea sorry, that example was a bit bad
<raz>
@[ART::Param("num", parse_as: IntegerParam, addl_options: "could go here")]
<FromGitter>
<Blacksmoke16> just a diff syntax to `ParamConverter`?
<raz>
i think that extra "Param" makes it clearer. i.e. give the converter class, and any optional arguments to it
<raz>
yea, it's pretty much the same i think. just "ParamConverter" sounds weird to me. as a user i want to declare a "Param" there.
<raz>
(minor difference, just what caught my eye)
<FromGitter>
<Blacksmoke16> sorry to be more clear
<FromGitter>
<Blacksmoke16> π and you cool with that syntax, i.e. getting/setting value from attributes, versus just returning the value
<FromGitter>
<Blacksmoke16> bit more verbose, but also a bit more flexible
<raz>
hmm, what do you mean by returning the value?
<raz>
ohhhhh
<raz>
you mean *in* the converter class
<FromGitter>
<Blacksmoke16> yea, currently the `#convert` method returns the converted value
<FromGitter>
<Blacksmoke16> this would make it set it on the `request` object, and essentially return `nil`
<raz>
yea that looks fine to me. these converters are prob not written/changed often anyway. (just write one for each type, then forget about them)
<raz>
if plain out returning the value is also possible, that might feel more natural, but doesn't seem like a biggie to me
<raz>
(more natural = one less thing that could go wrong, like forgetting the syntax or accidentally writing it to a wrong place or such)
<FromGitter>
<Blacksmoke16> yea, ideally they would be semi generic, i.e. `@[ART::ParamConverter("user", converter: DBConverter, model: User)]`, then in code you could do like `configuration.options[:model].find id`
<raz>
yup i'm not familiar enough with athena to know what that would take. if it's a major undertaking i'd say the current way is plenty fine, too
<FromGitter>
<Blacksmoke16> mainly just separation of concerns
<raz>
in 99% of cases i personally likely wouldn't even use a converter but just stick with the primitive types (integer, string) and do lookups etc. in the handler-body
<raz>
cause otherwise i have to think about how to do error handling when the converter fails etc.
<FromGitter>
<Blacksmoke16> would still need to do that in the handler tho no?
<FromGitter>
<Blacksmoke16> converter is there to remove that boiler plate, of the query, what if its missing, etc
<FromGitter>
<Blacksmoke16> granted if you only looking up one or two things, prob not worth it
<raz>
yes, but there i know how to do it cause i do it all the time. converters i'd likely just use for very basic things like `String -> Time?`. not for sth like a user-lookup.
<FromGitter>
<Blacksmoke16> fair enough
<raz>
(but that's just a mindset thing. if error handling with converters is obvious enough, i might use them for more elaborate stuff too)
<raz>
Blacksmoke16: yep, but where do i get that exception? like if in my handler if want to display a different thing depending on whether user was found / not found / lookup error
<FromGitter>
<Blacksmoke16> @neutrinog `#write` now returns the number of bytes written
<FromGitter>
<Blacksmoke16> versus `nil`
<FromGitter>
<neutrinog> @Blacksmoke16 but I'm not writing anything.
<FromGitter>
<Blacksmoke16> can you share the code that reproduces?
<FromGitter>
<Blacksmoke16> raz: i think i see what you mean. yea, if an error happens in a converter your handler wouldnt run
<FromGitter>
<neutrinog> It's just running `crystal spec` on the codebase.
<FromGitter>
<Blacksmoke16> so you would want to cover your bases there
<jhass>
mntmn_: you may need to bootstrap by cross compiling
<FromGitter>
<Blacksmoke16> @neutrinog try running with `--error-trace`?
<raz>
Blacksmoke16: yup. and i think that's fine. malformed URL = http 5xx. for more complicated stuff with more than 2 possible outcomes, well, why not do it in the method body :) (or some kind of before-handler like you need for auth anyway)
<raz>
http 4xx actually
<FromGitter>
<Blacksmoke16> mainly since im not a fan of duplicating essentially the same logic in every handler i need to go from and ID to a db obj
<raz>
yep, hence "before-handler'. not sure how athena does these atm.
<FromGitter>
<Blacksmoke16> when i can define the not found, invalid id, etc logic in a centralized place (that can be tested)
<raz>
like if you want to wrap multiple endpoints with auth (but not all of them).
<FromGitter>
<Blacksmoke16> but for what you want, would need another event that happens after arguments are resolved, but before handler is executed
<raz>
hmmm.
<FromGitter>
<Blacksmoke16> sadly i dont have anything specific to handling auth built in atm
<FromGitter>
<Blacksmoke16> its on my list
<FromGitter>
<neutrinog> @Blacksmoke16 I guessed it was from baked_file_system since that was the only lib I had that does IO. Adding the error trace confirmed that.
<FromGitter>
<Blacksmoke16> π
<raz>
yea actually... in my mind it would be something like @[ART::Before(DoAuthStuff)]. where DoAuthStuff has full access to the request-context and can make variables available to it (such as a `user`)
<raz>
kinda like your converters, except not bound to a specific param
<FromGitter>
<Blacksmoke16> thats what listeners are no?
<raz>
ah, good! - i haven't dabbled with athena so didn't know :)
<FromGitter>
<Blacksmoke16> it wouldnt be as specific as annotating a method tho
<raz>
well for auth it has to be
<FromGitter>
<Blacksmoke16> would be global for all endpoints, and the listener would need to determine if it should act
<FromGitter>
<Blacksmoke16> then the listener could check for a like `ART::Security` annotation, and noop if its not there
<FromGitter>
<Blacksmoke16> but i havent thought too much about this side of things yet
<raz>
yup, not sure how it can be implemented. that's just what i need it as a user. just like your ParamConverter is specific to a handler, things like auth also need to be
<raz>
(bonus points for being able to wrap it around multiple handlers w/o having to repeat the annotation - but that's already in the luxury dept)
<FromGitter>
<Blacksmoke16> id prob make it so you could add the annotation to the class to affect all handlers within it
<raz>
yea, would worry about that last. per-endpoint is the important bit.
<FromGitter>
<neutrinog> is there a nightly version of the api docs somewhere?
<raz>
as an impl idea, you could probably also do the per-endpoint constraint "in reverse". e.g. DoAuthStuff could be a Listener that runs for every request. but have a guard in it that looks up the id of the called endpoint whitelist. that whitelist could then be populated with annotations at compile time.
<FromGitter>
<Blacksmoke16> need to add a section on error handling, but that should make for a bit better intro when navigating to the docs
<raz>
in a whitelist*
<raz>
yay, docs!
<FromGitter>
<Blacksmoke16> maybe as a MVP, otherwise security is usually more in depth than white/blacklist
<FromGitter>
<Blacksmoke16> like what we do at work `@Security("has_role('ROLE_ACTIVE_CUSTOMER') and has_role('ROLE_RECRUITING_USER') and has_role('ROLE_FEATURE_INTERVIEWS')")`
<raz>
true, i didn't explain it well. there could still be multiple listeners of course. or one listener that behaves differently depending on which endpoint was called.
<FromGitter>
<Blacksmoke16> ah true true
<raz>
yea... you'll figure it out :)
<FromGitter>
<Blacksmoke16> like a simple whitelist handler
<FromGitter>
<Blacksmoke16> listener*
<raz>
(whitelist was also misleading, i guess the annotation would write the params for the listener-call in there)
<FromGitter>
<Blacksmoke16> most of the work would be behind the scenes. as i would now need built in ways to determine *how* to authenticate a given user
<FromGitter>
<Blacksmoke16> or determine what roles/permissions they have
<FromGitter>
<Blacksmoke16> and*
<raz>
well, that's what the listener would do (to be implemented by the framework user)
<raz>
it could check http auth headers, cookies, or whatever the dev desires
<FromGitter>
<Blacksmoke16> i suppose i could start simpler
<FromGitter>
<Blacksmoke16> lay the ground work and can always build upon it
<raz>
yup yup. i think "per-endpoint listener" is the goal. since your listeners basically behave like middleware (run for all requests). so the annotation would only need to be able to provide the per-endpoint params it (and the information whether it should run for a given endpoint).
<raz>
to it*
<FromGitter>
<neutrinog> hey, it appears you have to manually count how many bytes you write to `IO`. Is that true or did I miss something?
<FromGitter>
<neutrinog> The problem I'm getting is related to a line like this `IO.copy file, encoder` where encoder is is a subclass of `IO` that implements a write method without returning the number of bytes.
<FromGitter>
<Blacksmoke16> afaik just needs to add a `slice.size` at the bottom?
<raz>
blacksmoke16: https://carc.in/#/r/94yj (just to clarify the idea in pseudo-code, i.e. how i think you could still keep your listeners global but constrain them to individual endpoints with annotations)
<FromGitter>
<Blacksmoke16> ah, yea im not super familiar with this :/
<FromGitter>
<neutrinog> np. I was just wondering if IO could tell me how many bytes it received or if I had to do it manually. Which is better, etc.
alexherbo2 has joined #crystal-lang
<FromGitter>
<neutrinog> I'm pretty certain the answer is no, it cannot, but thought I'd double check.
<FromGitter>
<Blacksmoke16> i think you would know the size of the slice, but would just need to account for the extra stuff?
<FromGitter>
<neutrinog> that's the way it looks.
<FromGitter>
<neutrinog> on a different note is something like this `def hello(arg, *, another_arg)` simply making use of the splat to force the subsequent args to be named arguments?
<FromGitter>
<neutrinog> because you can't actually use the `*` by itself right?
deavmi has quit [Quit: Eish! Load shedding.]
deavmi has joined #crystal-lang
<FromGitter>
<Blacksmoke16> thats already a thing
<FromGitter>
<Blacksmoke16> its not named so isnt a way to reference it
<FromGitter>
<naqvis> When a splat method argument has no name, it means no more positional arguments can be passed, and next arguments must be passed as named arguments.
deavmi has quit [Quit: Eish! Load shedding.]
iwq has quit [Ping timeout: 246 seconds]
deavmi has joined #crystal-lang
deavmi has quit [Read error: Connection reset by peer]
deavmi has joined #crystal-lang
deavmi has quit [Read error: Connection reset by peer]
deavmi_ has joined #crystal-lang
<oprypin>
neutrinog, no it's not "making use of splat" seeing as splat args are not allowed then
<oprypin>
it is a special syntax but in line with what's familiar
iwq has joined #crystal-lang
deavmi_ has quit [Read error: Connection reset by peer]
deavmi has joined #crystal-lang
<oprypin>
both `*` and `*args` signify that following args are keyword-only, but `*` is not the same as `*never_use_these`
hightower2 has quit [Remote host closed the connection]
alexherbo25 has joined #crystal-lang
alexherbo2 has quit [Ping timeout: 272 seconds]
alexherbo25 is now known as alexherbo2
HumanGeek has quit [Ping timeout: 256 seconds]
HumanG33k has joined #crystal-lang
<FromGitter>
<neutrinog> thanks for the clarification @oprypin
alexherbo21 has joined #crystal-lang
alexherbo2 has quit [Ping timeout: 260 seconds]
alexherbo21 is now known as alexherbo2
gangstacat has quit [Quit: Δis!]
gangstacat has joined #crystal-lang
<FromGitter>
<Blacksmoke16> Hm raz might to revisit somethings
deavmi has quit [Quit: Eish! Load shedding.]
<FromGitter>
<Blacksmoke16> `missing key 'type' for named tuple NamedTuple(converter: DoubleConverter.class)`
<FromGitter>
<Blacksmoke16> unions
deavmi has joined #crystal-lang
<FromGitter>
<Blacksmoke16> is tricky, got this working
<FromGitter>
<Blacksmoke16> better solution would be to define specific metadata types for each converter
deavmi has quit [Read error: Connection reset by peer]
deavmi_ has joined #crystal-lang
<raz>
yup, i think that's basically the "arbitrary mixed-type tuples" problem i cried about the other day
<FromGitter>
<Blacksmoke16> pretty much
<FromGitter>
<Blacksmoke16> ill have to think on it
<raz>
yea, haven't found a great solution to it since then. it's either more verbosity (addtl struct / class) or rather hell'ish macros.
<raz>
sometimes one can cheat by passing **kwargs around, but that's very case-dependentt
<FromGitter>
<Blacksmoke16> prob end up going the additional struct route. problem then would be how to know which one to use
<raz>
yup, that very much depends on the details. tends to be an arm-wrestle between macro & runtime context
<FromGitter>
<Blacksmoke16> possibly something like `@[ART::ParamConverter("value", metadata: DoubleConverterMetadata)]`
<FromGitter>
<Blacksmoke16> actual converter can be derived from the metadata, plus could contain things directly related to it
<FromGitter>
<Blacksmoke16> i.e. back to `@[ART::ParamConverter("value", metadata: MultiplyConverterMetadata, by: 3)]`
<raz>
yea, although, if you pass DoubleConverter *and* DoubleConverterMeta you could perhaps just ask the user to make a separate converter for each case himself
<raz>
so he has to fiddle with only one (sub-)class instead of two
<raz>
it's tricky tho in either case...
<FromGitter>
<Blacksmoke16> well they are two different things
<FromGitter>
<Blacksmoke16> metadata would contain like extra values supplied in the annotation that would determine how the actual converter obj functions
<FromGitter>
<Blacksmoke16> sec, let me make an example
<raz>
ah true, gotcha
<raz>
well, perhaps, with some macro trickery, the *Metadata class could be autogenerated and hidden from the user, hmm.
<raz>
(not sure if that's doable with annotations at play tho)
<raz>
phew. yea, i guess that could work. but tbh, would not be keen on having to write/remember such a thinig
<raz>
(pure boilerplate)
<FromGitter>
<Blacksmoke16> kinda sucks, because you need three types to handle this, the annotation, the metdata, and the actual converter. Would be nice if the annotation was the metadata
<raz>
yep, +1 on the last bit
<raz>
my belly feeling is a convoluted macro could get you there. but... don't ask for details plz :D
<raz>
(cause it's really just a feeling, not sure how/where)
<FromGitter>
<Blacksmoke16> what about `@[ART::ParamConverter("num", converter: MultiplyConverter, by: 3)]`, then just assuming the metadata is converter name + `Metadata`
<raz>
yes, that's the direction i'm thinking. and ideally the +Metadata struct/class would be auto-generated so the user doesn't have to even know it exists
<FromGitter>
<Blacksmoke16> auto-generated based on what?
<FromGitter>
<Blacksmoke16> i couldnt possibly know
<raz>
i guess more annotations in the MultiplyConverter class
<raz>
it's the one that wants the "by"-parameter, right?
<raz>
(well, annotations or setter-style macros... that's why my idea gets blurry)
<raz>
why/where*
<FromGitter>
<Blacksmoke16> could work for simple cases, but i could also see like optional, or defaulted values
<raz>
...very blurry
<FromGitter>
<Blacksmoke16> which i wouldnt know about
<raz>
yup yup
<FromGitter>
<Blacksmoke16> granted as you said before, these wont be super common, so being a bit more verbose for some compile time safety/flexibility is prob alright
<FromGitter>
<naqvis> wow, thank you @Blacksmoke16
<FromGitter>
<Blacksmoke16> also the libraries section might be helpful too?
<FromGitter>
<naqvis> π
<FromGitter>
<naqvis> but thing is, those are OS dependent
<FromGitter>
<naqvis> on OSX they are different than on *nix and similarly on Windows
<FromGitter>
<naqvis> though Windows isn't in my radar atm lol
<FromGitter>
<Blacksmoke16> cant determine what OS you're on and run the corresponding code? could use a bash script as well
<FromGitter>
<naqvis> yeah true
<FromGitter>
<naqvis> i was talking about those 'libraries` section of shard.yml
<FromGitter>
<Blacksmoke16> ah gotcha
<FromGitter>
<naqvis> isn't that static content?
<FromGitter>
<Blacksmoke16> prob?
deavmi has joined #crystal-lang
<FromGitter>
<naqvis> for this use-case, libraries are system dependent and they will be different on each OS
<FromGitter>
<naqvis> so having listing all platforms libraries good?
<FromGitter>
<Blacksmoke16> given its just informational, prob dont need to get too specific?
<FromGitter>
<naqvis> e.g. on OSX it will require `Cocoa/WebKit` while on Linux it will be relying on `Gtk-webkit2` and on windows it will be `MSHTML or EdgeHTML`
<FromGitter>
<naqvis> yeah
deavmi has quit [Read error: Connection reset by peer]
deavmi has joined #crystal-lang
return0e has joined #crystal-lang
deavmi_ has joined #crystal-lang
deavmi has quit [Read error: Connection reset by peer]
return0e has quit [Remote host closed the connection]
<FromGitter>
<Blacksmoke16> raz: i thought about it a bit more
<FromGitter>
<Blacksmoke16> new plan :P
<FromGitter>
<Blacksmoke16> have a default metadata object for the cases where the converter doesnt need extra data
<FromGitter>
<Blacksmoke16> and add an optional constant to the converter to specify the metadata obj it should use (defaulting to the built in empty one if missing)
<raz>
yup, looks good to me. quite java'ish, but solid
<raz>
and terse where it needs to be (in the actual method annotations)
<FromGitter>
<Blacksmoke16> could make some macro to define the initializer that would hide the name/converter so user just have to define the new stuff but :shrug:
<raz>
yup, if it was my thinger i would probably try to hide the above two behind a macro.
<FromGitter>
<Blacksmoke16> hm
<FromGitter>
<Blacksmoke16> ```metadata MultiplyConverterMetadata, by : Int32````
<oprypin>
@naqvis: whaaa that's so weird, is the library really 3 separate things on separate platforms?
<oprypin>
also edgehtml is discontinued π¬
<oprypin>
naqvis, egh it needs some CI π¬
<raz>
Blacksmoke16: ```create_converter(Multiply, by : Int32) { ...code that goes in the apply-method... }```
<raz>
:)
<FromGitter>
<Blacksmoke16> hmm
<FromGitter>
<Blacksmoke16> could work assuming the converter itself doesnt have any dependencies
<FromGitter>
<Blacksmoke16> or at least make those some named optional argument
<raz>
if it's even possible syntax-wise, not sure about that. kinda just typed out what i think i would like to write as a framework-user. (which naturally is: as few keystrokes as possible ;))
<FromGitter>
<Blacksmoke16> It is
<FromGitter>
<Blacksmoke16> Essentially just a wrapper around the record macro
<raz>
yup, well, it would also spare me from having to know what a ADI::Register is
<oprypin>
naqvis, and as a suggestion, i just dont like this `darwin/` subdirectory stuff. i'd put it into one directory.
<FromGitter>
<Blacksmoke16> That's where the real magic happens ha
<raz>
i can imagine. thing is... unless i _have_ to know about it in common usage, i'd prefer not to ;)
<raz>
like if i'm just typing out my API handlers and stuff, i like some cushion between me and the magic machinery
zorp_ has joined #crystal-lang
<FromGitter>
<Blacksmoke16> I'm definitely going to keep this in mind, but focus on the structure/lower level side of things for now. Probably do another pass to add some abstractions
<raz>
yup, sounds like a good plan
<FromGitter>
<Blacksmoke16> Then can be assured all that is working well
<raz>
yep, syntax sugar can also backfire when things are still in flux
<FromGitter>
<Blacksmoke16> Indeed
<FromGitter>
<Blacksmoke16> Especially since it's a bit more advanced feature and probably won't be too many of them
<FromGitter>
<Blacksmoke16> Debating if I want to supply some built in ones
alexherbo2 has quit [Ping timeout: 272 seconds]
alexherbo2 has joined #crystal-lang
alexherbo2 has quit [Ping timeout: 240 seconds]
zorp_ has quit [Ping timeout: 258 seconds]
oprypin has quit [Remote host closed the connection]
oprypin has joined #crystal-lang
FromGitter has quit [Remote host closed the connection]