ChanServ changed the topic of #crystal-lang to: The Crystal programming language | http://crystal-lang.org | Crystal 0.33.0 | Fund Crystal's development: http://is.gd/X7PRtI | GH: https://github.com/crystal-lang/crystal | Docs: http://crystal-lang.org/docs/ | API: http://crystal-lang.org/api/ | Gitter: https://gitter.im/crystal-lang/crystal
<postmodern> interesting that Time.now was removed. i assume that was to force users to consciously choose between .utc and .local?
<FromGitter> <Blacksmoke16> Yes
<postmodern> hmm also rather like URI.escape/unescape being aliases. Also guessing crystal has a policy on avoiding aliasing in the stdlib?
<FromGitter> <Blacksmoke16> Yes
<FromGitter> <tenebrousedge> yes, Crystal stdlib avoids aliases
<FromGitter> <yorci> ```Unhandled exception in spawn: connect: Connection timed out (Errno)```
<FromGitter> <yorci> i got this error
<FromGitter> <yorci> any ideas about cause ?
<postmodern> which is preferred `var.in?(collection)` or `collection.includes?(var)`?
<FromGitter> <Blacksmoke16> @yorci the server isn't responding in time or something like that
<FromGitter> <Blacksmoke16> Uh, whichever reads better? They're essentially the same
<FromGitter> <yorci> could be cause from channel?
<FromGitter> <Blacksmoke16> Depends on the context
<FromGitter> <Blacksmoke16> Timeout is pretty general
<FromGitter> <dscottboggs_gitlab> What's the deal with `Pointer`? All 3 `.malloc` overloads call each other except this one (https://github.com/crystal-lang/crystal/blob/612825a53c831ce7d17368c8211342b199ca02ff/src/pointer.cr#L435-L441) which just calls a global `malloc` which seems to not exist. I tried seeing if ⏎ ⏎ ```require "c/string" ⏎ malloc 1``` ⏎ ⏎ worked and it doesn't so there has to be something else going on
<FromGitter> <Blacksmoke16> Probably built into the compiler?
alexherbo2 has quit [Quit: The Lounge - https://thelounge.chat]
<FromGitter> <dscottboggs_gitlab> if that's the case then why can't I just call it from any source file?
<FromGitter> <Blacksmoke16> yes
<FromGitter> <dscottboggs> Can't
<FromGitter> <Blacksmoke16> naw idk, `codegen.cr` has some references to it
<FromGitter> <Blacksmoke16> so yea is prob some fancy meta method or something
<FromGitter> <dscottboggs> I'm just trying to understand why `LibC.malloc` allocates a whole bunch of extra memory. Like...a MB+
<FromGitter> <Blacksmoke16> :shrug
<FromGitter> <dscottboggs_gitlab> it looks like, consistently, once a pointer allocated by `LibC.malloc` is freed by `LibC.free`, there is exactly 2MB extra memory which is stored. I can assume this is GC'd at some point (assuming the GC works), but it seems like a crzy high amount of memory to store a `Pointer(Void)`
<FromGitter> <tenebrousedge> o.o
<FromGitter> <dscottboggs_gitlab> I would post the way I figured this out but it's hacky AF
<FromGitter> <tenebrousedge> I need all the hacks
<FromGitter> <tenebrousedge> so I can be a 1337 h4xX0|2
<postmodern> how do you specify a type enforcement for a certain #to_* method, such as #to_slice?
<postmodern> doesn't appear to be a Sliceable module
<FromGitter> <dscottboggs_gitlab> okay so I ran this ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ as you'll see, regardless of the value of `SIZE` it works [https://gitter.im/crystal-lang/crystal?at=5e4c9b1ed97c107ed25ffa09]
<FromGitter> <dscottboggs_gitlab> if you bother to run through all my bullshit hacks.
<FromGitter> <tenebrousedge> postmodern: wat??
<FromGitter> <dscottboggs_gitlab> @postmodern do you mean that you want to check `x.responds_to? :to_slice`? <- that is how you do that
<FromGitter> <tenebrousedge> @dscottboggs_gitlab well that's interesting at any rate
<postmodern> dscottboggs_gitlab, i noticed that in two places in stdlib, there are docu NOTEs saying the given variable must respond to #to_slice. I found it odd that there's not a way of indicating/enforcing that with the type system and it got me thinking.
<FromGitter> <dscottboggs_gitlab> yes, the crystal type system is kind of weird. Since the method you're referring to calls `#to_slice` on its argument, the compiler will enforce (at compile time) that the `#to_slice` method is implemented by any type passed to that method as that argument. Does that make sense?
<postmodern> ah so defining "interfaces" or abstract classes are not really necessary when requiring a specific method be available
<FromGitter> <watzon> Ok question for someone that knows macros well (I'm looking at you @Blacksmoke16). Can you think of a good way in which I could have a middleware add methods to a client, ideally without using `method_missing`? ⏎ ⏎ For instance, I have a class that acts very much like an HTTP client, and it has middleware. Right now I have some functionality that I want to refactor and turn in to middleware, but currently
<FromGitter> ... the modules that I'm trying to refactor actually add methods to the client. The only problem is, the registered middleware isn't necessarily known at compile time. I'd like to be able to loop over the middleware, look for an `@[Export]` annotation over certain methods, and attach those methods to the client, but I don't know if ... [https://gitter.im/crystal-lang/crystal?at=5e4ca3fadafa3029f63c3cb7]
<FromGitter> <watzon> I'd love to give an example, but thinking of a minimal example for something like this isn't easy
<FromGitter> <Blacksmoke16> :thinking:
<FromGitter> <Blacksmoke16> you would be correct, the PR that would allow that isnt merged/approved yet
<FromGitter> <Blacksmoke16> you could do something like what i do for DI shard, use a module + an annotation
<FromGitter> <Blacksmoke16> that way you can iterate over types that include the module, and access the annotation
<FromGitter> <Blacksmoke16> module or parent type are really only two ways atm
<FromGitter> <watzon> What's the PR you're referring to?
<FromGitter> <Blacksmoke16> without hacky shit like adding values to constants in macros
<FromGitter> <watzon> I'd be fine with hacky shit btw haha
<FromGitter> <watzon> As long as it works for now
<FromGitter> <Blacksmoke16> module would prob be the better approach
<FromGitter> <watzon> Ahh I do like that PR
<FromGitter> <tenebrousedge> postmodern, right, Crystal is "duck typed" to some degree, where we don't care if something *is a* Foo, only if it responds to `foo_method`
<FromGitter> <Blacksmoke16> whats your ideal UX here?
<FromGitter> <Blacksmoke16> like is a middleware just a type that implements `#call` or something?
<FromGitter> <watzon> Basically. It implements `#call` and potentially an `#init` function that's called when it gets registered.
<FromGitter> <Blacksmoke16> and how do they get registered?
<FromGitter> <Blacksmoke16> similar to `HTTP::Server` where you pass it an instance of them?
<FromGitter> <Blacksmoke16> array of instances*
<FromGitter> <watzon> Yep, exactly like that
<FromGitter> <watzon> Basically `client.use(MyMiddleware.new)`
<FromGitter> <watzon> And it puts it into an array
<FromGitter> <watzon> And then on every update we loop over the array and call all the registered middleware
<FromGitter> <Blacksmoke16> the user should be able to specify which middleware it should use? Or should the client use all middleware avaliable
<FromGitter> <watzon> The user specifies, but there are some middleware that are registered by default
<FromGitter> <watzon> Those are the ones I'm attempting to make right now
<FromGitter> <watzon> Well I should say they specify which ones are registered, all middleware that are registered get called on each update
<FromGitter> <Blacksmoke16> what about
<FromGitter> <Blacksmoke16> is the client something the user defines or?
<FromGitter> <watzon> Yes. In most cases the user extends the client. So they'll do ⏎ ⏎ ```MyBot.command("echo") do |ctx| ⏎ # do something ⏎ end``` ⏎ ⏎ and that's where the need to have middleware add methods to the client comes in [https://gitter.im/crystal-lang/crystal?at=5e4ca8c089f30b12651703f6]
<FromGitter> <watzon> The annotation I can handle in the middleware, but not the `command` method
<FromGitter> <Blacksmoke16> well if you have each middleware type include a module you can iterate over them
<FromGitter> <Blacksmoke16> would that not solve the problem?
<FromGitter> <Blacksmoke16> which you could probably add within the parent type in a macro inherited so that it could add those methods when its inherited
<FromGitter> <Blacksmoke16> could even add an annotation or something to the child client type to say which middleware it should use?
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <dscottboggs_gitlab> I was thinking that you could have a macro which defines the method, like `bot(MyBot).command "echo" do |ctx|...` but that makes me wonder... is there a way to check if a given type exists yet or not?
<FromGitter> <Blacksmoke16> prob
<FromGitter> <watzon> Hmm I'll have to think on that @Blacksmoke16, I think that could work
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/8l2z
<FromGitter> <Blacksmoke16> prob a bit of a hack but :shrug:
<postmodern> tenebrousedge, i assume the type inference takes care of some of the duck typing
<FromGitter> <dscottboggs_gitlab> @Blacksmoke16 woah
<FromGitter> <dscottboggs_gitlab> postmodern yes, exactly
<FromGitter> <dscottboggs_gitlab> Type restrictions are a way to manually specify that a method expects a specific type, but if you don't want to specify, compatibility can be determined by the inference system by method names only
<FromGitter> <tenebrousedge> postmodern, yes, sort of. It's more of a philosophy in some senses. Ruby has duck typing without a type system
<FromGitter> <tenebrousedge> well, without an explicit type system at any rate
<FromGitter> <tenebrousedge> Ruby takes this one step further than Crystal, because in Ruby the available methods for any given object are totally dynamic
<FromGitter> <tenebrousedge> you can have a single string instance with a `foo` method defined on it, and undefine all other methods if you like
<FromGitter> <tenebrousedge> the type is usually indicative that it has x, y, z methods available, but not always
<FromGitter> <tenebrousedge> in Crystal you can't have instances of objects with their own methods defined, so type is a much more reliable indicator of what methods are available
<FromGitter> <dscottboggs_gitlab> > you can't have instances of objects with their own methods defined ⏎ ⏎ what do you mean by this?
<FromGitter> <tenebrousedge> but it's still often expressed as, "the object must implement `to_slice`" rather than extending or using a specific interface
<FromGitter> <tenebrousedge> @dscottboggs_gitlab in Ruby you can do: ⏎ ⏎ ```a = "foo" ⏎ def a.bar ⏎ self + "bar" ⏎ end ⏎ a.bar #=> "foobar"``` [https://gitter.im/crystal-lang/crystal?at=5e4cac6f14b4d670a333a7b6]
<FromGitter> <dscottboggs_gitlab> oh jeeze
<FromGitter> <dscottboggs_gitlab> yeah
<FromGitter> <dscottboggs_gitlab> same with other dynamic languages in some way or another
<FromGitter> <tenebrousedge> Ruby is one of the more dynamic of the dynamic languages. Almost everything can be redefined at runtime
<FromGitter> <dscottboggs_gitlab> "the object must implement `#to_slice`" is just another way of saying "the object must implement the `Slicable` interface" it's just more implicit
<FromGitter> <tenebrousedge> you can't eliminate some form of assignment, and that may be the only real restriction
<FromGitter> <Blacksmoke16> 🔪
<FromGitter> <dscottboggs_gitlab> knife?
<FromGitter> <Blacksmoke16> A bad slicable joke
<FromGitter> <dscottboggs_gitlab> oh hahaha
<postmodern> hmm i upgraded to crystal 0.33.0 via snap, but now `shards install` is asking for my username when git pulling' from https://gitlab.com/. pretty sure i don't need to authenticate to pull from a public repo
<FromGitter> <Blacksmoke16> What shard version
<FromGitter> <Blacksmoke16> Also was it working before?
<FromGitter> <tenebrousedge> it is relatively useful in Ruby to be able to give specific objects a method or set of methods, rather than e.g. reopening String. In Crystal you're forced to use some sort of wrapper object. It would be nice if there was some sort way to locally mess with objects. But it's probably for the best
<FromGitter> <dscottboggs_gitlab> postmodern usually that means the repo name is misspelled
<postmodern> Blacksmoke16, Shards 0.8.1 [0147a56] (2020-02-14) and appears to happen for new shards that it hasn't already pulled down
<FromGitter> <Blacksmoke16> whats your shard.yml look like?
<postmodern> ah nevermind, dscottboggs_gitlab is correct. Shard example from the README is wrong.
<FromGitter> <dscottboggs_gitlab> that'll do it
<FromGitter> <dscottboggs_gitlab> if docs are broken please report the issue
<postmodern> weird, crodoc is hosted by fossabot, but has watzon's name all throughout the README. Doesn't look forked.
<postmodern> bummer that ',' in enums were deprecated. Support the ',' character allows one to copy/paste C enums into crystal.
<FromGitter> <Blacksmoke16> would the formatter fix it?
<FromGitter> <dscottboggs_gitlab> it used to
<FromGitter> <dscottboggs_gitlab> also there's `sed` or `String#gsub`
<postmodern> yeah just did some vim sed magic
<FromGitter> <dscottboggs_gitlab> vim's `s` command is great
<FromGitter> <dscottboggs_gitlab> did you try `crystal tool format` though?
<postmodern> nnoremap / /\v
<postmodern> cnoremap %s/ %s/\v
<postmodern> for maximum sed action
<postmodern> wait, fossabot/crodoc is empty. i've been tricked!
<FromGitter> <dscottboggs_gitlab> you've been tricked???
<postmodern> bamboozled even. i was hoping there was a yard/javadoc style documentation formatter. prefer tag style docs vs. italicizing argument names.
<FromGitter> <dscottboggs_gitlab> what do you mean? Crystal has automatically generated docs that use markdown formatting
<postmodern> the benefit of tags is you can annotate individual params, examples, different return values, and different exceptions, and specifically what they mean.
ur5us has quit [Ping timeout: 240 seconds]
<FromGitter> <watzon> @postmodern weird, I just looked it up. I think I'd added fossabot to crodoc (which I haven't worked on in quite a while).
<FromGitter> <watzon> The link on shards.info is just pointing to the wrong place I guess
<postmodern> watzon, also appears you deleted crodoc?
<FromGitter> <watzon> Crystal's doc generation is severely limited, so I definitely want to start working on it again
<FromGitter> <watzon> I think I made it private
<FromGitter> <watzon> Because it doesn't actually work right now
<postmodern> ah ha
<postmodern> hope you get it up and running. all of my ruby libraries have yardoc. would be nice to port over the yardocs as well.
<FromGitter> <watzon> Yeah I agree.
<FromGitter> <tenebrousedge> Crystal should def have yardoc
<FromGitter> <watzon> yardoc is really nice
<FromGitter> <watzon> I like the custom formatters, groups, etc
<FromGitter> <watzon> Crystal's documentation generation is very, very limited
<postmodern> possibly crodoc could expose the inferred types of things?
<postmodern> one of the features of yardoc is you can specify an argument must respond to a method with @param [#foo] arg1
<FromGitter> <dscottboggs_gitlab> > you can annotate individual params, examples, different return values, and different exceptions, and specifically what they mean. ⏎ ⏎ Hm, I kinda see what you mean about being able to make notes beyond type about a parameter of a method. ⏎ ⏎ Everything else you mentioned is handled by type annotations, except Exception documentation. I've brought up before that it would be good to be able
<FromGitter> ... to specify that a method can't raise an exception, but that got shot down. ... [https://gitter.im/crystal-lang/crystal?at=5e4cb68e40ac4a7fb9f385c3]
<FromGitter> <watzon> I don't think it would be possible to expose inferred types using the compiler, but I could definitely include a `@param` annotation allowing you to specify. That was actually one of my plans. By default it will base it off of type annotations, if they're included, but a `@param` annotation could overload it.
<FromGitter> <dscottboggs_gitlab> > but a @param annotation could overload it. ⏎ why?
* FromGitter * watzon shrugs
<FromGitter> <watzon> I never presume to know what someone else's use case might be
<FromGitter> <watzon> I just like throwing features at the wall and seeing what sticks
<FromGitter> <dscottboggs_gitlab> great idea then we wind up with C++
<FromGitter> <tenebrousedge> c++ is a great language that everyone uses and loves
<FromGitter> <tenebrousedge> pretty sure
<FromGitter> <watzon> Lmao. Well I'm not talking about adding things to the language itself. Nothing wrong with a library that's full of features though.
Nicolab has joined #crystal-lang
<FromGitter> <dscottboggs_gitlab> C++ has a lot of the right features and the wrong abstractions
<FromGitter> <watzon> Agreed
<postmodern> dscottboggs_gitlab, also tags are easier to write out. I found myself constantly writing extra boilerplate text and remembering to italicize arguments back when i used rdoc. switching to yardoc was a huge productivity boost.
<FromGitter> <watzon> Made crodoc public again and I'm gonna start working on it. Wish me luck.
ur5us has joined #crystal-lang
<postmodern> watzon, thank you. i'll take a look.
<postmodern> is there a shorthand for writing a ASCII string literal?
<FromGitter> <tenebrousedge> ...
<FromGitter> <tenebrousedge> "abc"
<FromGitter> <dscottboggs_gitlab> do you mean a byte string?
<postmodern> yes a string encoded as US-ASCII 8bit
<FromGitter> <dscottboggs_gitlab> file:///usr/share/doc/crystal/api/String.html#encode(encoding:String,invalid:Symbol?=nil):Bytes-instance-method
<FromGitter> <dscottboggs_gitlab> shit
<FromGitter> <dscottboggs_gitlab> @postmodern https://crystal-lang.org/api/0.33.0/String.html#encode(encoding:String,invalid:Symbol?=nil):Bytes-instance-method
<FromGitter> <tenebrousedge> does the bit encoding actually differ for the first 128 chars of UTF-8 ?
<FromGitter> <dscottboggs_gitlab> @tenebrousedge no
<FromGitter> <dscottboggs_gitlab> if you can ensure externally that the string actually only contains valid ascii characters, you can just do `"some string that only contains valid ascii".bytes`
<FromGitter> <tenebrousedge> that's what I thought
<FromGitter> <dscottboggs_gitlab> (or if you just don't care to check 😆)
<FromGitter> <dscottboggs_gitlab> you could even just do a rudimentary ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5e4cbd9cb662483a874eb0cd]
<FromGitter> <tenebrousedge> or you could do `each_byte` instead of `bytes.tap &.each` if you don't mind the iterator
<FromGitter> <dscottboggs_gitlab> ah you're right good catch
<FromGitter> <tenebrousedge> or `each_char`, rather
<FromGitter> <tenebrousedge> I think?
<FromGitter> <dscottboggs_gitlab> `each_char` returns every UTF-8 codepoint, not every char
<FromGitter> <dscottboggs_gitlab> you want every byte in this case IMO
<FromGitter> <dscottboggs_gitlab> also I feel like it would be slightly faster given the particular situation
<FromGitter> <tenebrousedge> duh, right, because 2^8 is 256 not 128
<FromGitter> <tenebrousedge> it's late
<FromGitter> <dscottboggs_gitlab> also, if you're reading it in from some sort of `IO`-able input, like a file, socket, etc., you could just read it in as a `Bytes` or `Array(Int32)` and do the checks there, or perhaps define a custom ASCII-string type. I should make a shard that does that -- an importable ASCII string....but it's bedtime.
<FromGitter> <dscottboggs_gitlab> holy crap, look at this https://crystal-lang.org/api/0.33.0/String.html#succ-instance-method
<FromGitter> <tenebrousedge> hmm?
<FromGitter> <tenebrousedge> that's been there for ages
<postmodern> what's a good crystal type to pass down to a function that takes a LibC::SizeT argument?
<FromGitter> <dscottboggs_gitlab> I'm not surprised that it's been there a while, I just never noticed and... wow. That's very complicated
<FromGitter> <tenebrousedge> there's also `Char#succ`
<FromGitter> <dscottboggs_gitlab> I think `LibC::SizeT` is the same as an `UInt64`
<postmodern> dscottboggs_gitlab, not on 32bit architectures, but those kind of went out of style
<FromGitter> <dscottboggs_gitlab> of course that's platform-specific
<FromGitter> <dscottboggs_gitlab> yeah
<postmodern> once everyone upgrades to arm64 phones, we'll be free of 32bit
<FromGitter> <dscottboggs_gitlab> looking into it a bit, sec
<FromGitter> <dscottboggs_gitlab> ah, here we are
<FromGitter> <dscottboggs_gitlab> ```alias SIZE_T = {% if flag? :bits32 %} ⏎ UInt32 ⏎ {% else %} ⏎ UInt64 ⏎ {% end %}``` ⏎ ⏎ The compile-time flag `bits32` will be defined on 32-bit architectures so this will define an architecture independent size-type [https://gitter.im/crystal-lang/crystal?at=5e4cc1ea89f30b126517317f]
<FromGitter> <websymphony_twitter> Sorry if this is a dumb question, new to Crystal. ⏎ ⏎ In Crystal is there a way to access class variables without defining a class method that exposes it? For example, a way to access `@@people_count` from `Person` class without defining `self.people_count`? ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5e4cc3878b2d4664ef0f4209]
<FromGitter> <websymphony_twitter> Separately, where do shards get installed locally, when added to shard.yml. Am trying to debug some behaviour for an installed shard. For eg, in ruby I could do `bundle open gem_name` which will provide the path to installed gem whose code I could manipulate. Can we do same in crystal?
<FromGitter> <Blacksmoke16> no
<FromGitter> <Blacksmoke16> and `./lib`
<FromGitter> <Blacksmoke16> in the project dir
<FromGitter> <Blacksmoke16> you can do `class_getter people_count : Int32 = 0` tho
<FromGitter> <Blacksmoke16> which essentially defines the class var and a getter
<FromGitter> <tenebrousedge> in `lib`, so far
<FromGitter> <tenebrousedge> maybe not there in the future. Hopefully `./vendor/shards`
<FromGitter> <websymphony_twitter> Ah, right. Thank you, that should work! :)
<postmodern> hmm wait, i accidentally overrode a method in Enumerable in the sub-class, but it appears the Enumerable method is still getting called? Does included modules override any sub-class methods, or is the sub-class supposed to be at the top of the inheritance stack?
<FromGitter> <Blacksmoke16> i think it would would look in current class, then modules, then parent maybe?
<postmodern> hmm probably some other issue in my code
<FromGitter> <watzon> Really wish pretty printing `Crystal::ASTNode` actually showed the tree, and not the source
<FromGitter> <watzon> Actually wish the Compiler was better documented haha. Maybe once I figure this shit out I'll write a blog post.
Nicolab has quit [Quit: Leaving.]
_ht has joined #crystal-lang
ur5us has quit [Ping timeout: 248 seconds]
<FromGitter> <watzon> Well got AST generation working thanks to @veelenga and the ameba project
<FromGitter> <watzon> Very nice of him to do all the hard work for me
<FromGitter> <watzon> :)
_ht has quit [Quit: _ht]
<FromGitter> <acoolstraw> heya
ur5us has joined #crystal-lang
<FromGitter> <acoolstraw> ```code paste, see link``` ⏎ ⏎ does this example from kemal's guide get the headers of the websocket request? [https://gitter.im/crystal-lang/crystal?at=5e4cdf49d97c107ed26080d2]
<postmodern> how do you define optional keyword arguments (aka options) that don't have a default value?
<FromGitter> <acoolstraw> well, you could make the default value null?
<FromGitter> <acoolstraw> in which case ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5e4ce0bc4880f07ed1e4e4d4]
<FromGitter> <acoolstraw> should work
<postmodern> acoolstraw, hmm would crystal take care of the implicit typing based on where those keyword args get passed to?
<FromGitter> <acoolstraw> no
<FromGitter> <acoolstraw> no matter which one you do first, it'll work
<FromGitter> <acoolstraw> ```foo(bar: "foo", dog: "Rocky") ⏎ foo(dog: "Rocky", bar: "foo")``` [https://gitter.im/crystal-lang/crystal?at=5e4ce1a70c451412667657dd]
<FromGitter> <acoolstraw> both work
<FromGitter> <acoolstraw> but if you do `foo("test", "test2")`, "test" will be bar and "test2" will be dog
<postmodern> can default arguments have the value of another keyword argument?
<postmodern> and do they same rules apply to macro definitions?
postmodern has quit [Read error: Connection reset by peer]
postmodern has joined #crystal-lang
<FromGitter> <veelenga> @watzon thanks. What are working on? Why do you need AST?
<FromGitter> <yxhuvud> The answer to the first question is clearly yes, though. `def foo(x=2, y=x); end ` works.
<postmodern> yxhuvud, apparently `macro ud_delegate(method, ud_method = method)` doesn't work. worked around it by defaulting `ud_method = nil` and doing `ud_method || method` in the body.
<FromGitter> <watzon> @veelenga attempting to write a documentation generator akin to yardoc
<FromGitter> <watzon> I'm tired of the built in documentation generation, and I don't want to just go the easy route of parsing the json output. I need more.
<FromGitter> <veelenga> I see. Sounds promising
<FromGitter> <j8r> @watzon too bad the crystal docs is not a separate project, plugged into the compiler
<FromGitter> <j8r> I remember proposing something like this in the past
<FromGitter> <j8r> an for the playground too
<FromGitter> <j8r> It always felt weird to me having HTML/CSS/JS projects inside the language
Nicolab has joined #crystal-lang
sagax has joined #crystal-lang
<FromGitter> <watzon> Agreed. The compiler not being documented is also a pain in the ass.
<FromGitter> <watzon> Oh well. I'll make due.
ur5us has quit [Ping timeout: 260 seconds]
<FromGitter> <acoolstraw> I mean yeah the built in documentation creates very confusing stuff
<FromGitter> <acoolstraw> it's a pain reading through
<FromGitter> <straight-shoota> @acoolstraw What's confusing with the API docs?
<FromGitter> <straight-shoota> @watzon Yeah the JSON format is crappy. It was just patched in to get at least some machine readable output. I've been thinking about improving that. So you would ideally just need the compiler to extract doc data and the representation can work separately.
<FromGitter> <636f7374> Crystal default Colorize will cause your program to be confusing, especially if it contains `Dpreview_mt`.
<FromGitter> <636f7374> I don't have time to find out what is causing this problem, I remade Colorize myself.
<FromGitter> <636f7374> Anyone want to implement WireGuard (https://github.com/WireGuard), BoringTun (https://github.com/cloudflare/boringtun) in Crystal? This can be very difficult.
<FromGitter> <636f7374> I'm curious how WireGuard converts TCP traffic to UDP, I need to research.
<FromGitter> <636f7374> And GPU programming with Crystal? CUDA? OpenCL? Rust has something similar.
<FromGitter> <636f7374> The State of GPGPU in Rust (https://bheisler.github.io/post/state-of-gpgpu-in-rust/)
<FromGitter> <smw> Is there no longer any way to get file 'stat' information from crystal stdlib? I'd specifically like to get the inode of a file. Old version of the API seem to have it, but new ones don't?
<FromGitter> <straight-shoota> Yeah, that was removed in #5584. inode is a very platform-specific detail and the stdlib API is supposed to be portable. See #8357 for further discussion.
<DeBot> https://github.com/crystal-lang/crystal/pull/5584 (Rename and rework File::Stat as File::Info) | https://github.com/crystal-lang/crystal/issues/8357 (Missing File::Info data.)
<FromGitter> <straight-shoota> Maybe you can illustrate your use case there?
<FromGitter> <smw> Looks like I can use File.same? (found from your link) for my current use case, but I second/third the idea of not hiding the platform specific information from the users.
<FromGitter> <smw> @straight-shoota Thanks for your help!
Human_G33k has joined #crystal-lang
alexherbo2 has joined #crystal-lang
<FromGitter> <smw> ```code paste, see link```
HumanG33k has quit [Ping timeout: 248 seconds]
<FromGitter> <smw> Actually it looks like I can do `File.new(path).info.@stat.@st_ino`
<FromGitter> <smw> Though I'm sure that's not a stable public API
<FromGitter> <smw> I feel like in ruby I'd be able to leave off the `@`s, why do I need them here?
postmodern has quit [Quit: Leaving]
<FromGitter> <straight-shoota> The `@` means accessing an instance variable. Without it, you're calling a method. Some ivars are exposed as methods, other's are not (but can still be accessed directly). That's the same in both Crystal and Ruby.
<FromGitter> <smw> Ahh! TIL. Thank you. I wrote a lot of ruby at one point and somehow missed that distinction.
<FromGitter> <straight-shoota> Accessing the ivar directly is possible, but as you guessed, not intended as a public API (it would be a method then). But I suppose there won't be many changes to that, so it's probably rather stable. But there won't be any deprecation messages etc. in case something changes. It's definitely not recommended.
<FromGitter> <straight-shoota> Yeah, it's not very common to access ivars directly from outside the object. Neither in Ruby nor in Crystal.
<FromGitter> <smw> This is a pretty simple private utility that I don't intend to publish, and which probably has a limited life span (famous last words). I think I'll take my chances, for now.
flips has quit [Quit: bbl ...]
flips has joined #crystal-lang
<FromGitter> <asterite> In Ruby there's `instance_variable_get(...)` for the same purpose. In Crystal we just use a different syntax
<FromGitter> <asterite> > Really wish pretty printing Crystal::ASTNode actually showed the tree ⏎ Yeah, I usually remove the `inspect` overload that forwards to `to_s`. I should maybe remove that once and for all.
Nicolab has quit [Quit: Leaving.]
<FromGitter> <wout> I'm porting a Ruby library to Crystal and so far it has been very educational. At some point, a series of errors are caught in a begin/rescue block where an api call is made. I have managed to translate most of them, except the following three: `Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError`.
<FromGitter> <wout> What Crystal's equivalents? Can anyone point me in the right direction?
<FromGitter> <Blacksmoke16> you can define your own exceptions
<FromGitter> <Blacksmoke16> in the case of built in exceptions to rescue with, idt there are many/any `HTTP` related ones
<FromGitter> <wout> Yes, I did that for some cases. But these are coming from the standard library.
<FromGitter> <wout> Ok.
<FromGitter> <wout> Thanks!
<FromGitter> <drum445> Hello, if I have a DBHelper class that has a class var with a postgres connection, how can I avoid this class varaible initialising during spec runs?
<FromGitter> <j8r> it could monkey-patched in the `spec_helper`
<FromGitter> <straight-shoota> database connections don't seem like something you should store in a class variable
<FromGitter> <drum445> how come?
<FromGitter> <drum445> where do you usually keep track of them sir?
<FromGitter> <straight-shoota> connections can easily break for some network issues or whatever. Crystal's db shard automatically maintains a pool of connections, you don't need to keep track of them. Just check out a connection when you need one and return it when the operation is finished.
<FromGitter> <drum445> But then you are initialising db connections inside of methods
<FromGitter> <drum445> also, this is for MongoDB so pooling may not apply
<FromGitter> <straight-shoota> What driver are you using? Is it based on crystal-db?
<FromGitter> <drum445> datanoise/mongo.cr - I don't believe it is. This is just a general style I follow tbh
<FromGitter> <drum445> I used it in ruby, db conns in class methods, what do you see as a problem with that?
<FromGitter> <straight-shoota> Okay, I can't say anything about mongo.cr
<FromGitter> <straight-shoota> The problem is: what happens when the connection breaks?
<FromGitter> <straight-shoota> You'd need some way to reinitialize it
<FromGitter> <drum445> A new one is picked up
<FromGitter> <drum445> That isn't a problem for NoSQL connections usually
<FromGitter> <straight-shoota> Why not?
<FromGitter> <drum445> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5e4d57814609ce3a8811b309]
<FromGitter> <drum445> I've never seen it be an issue
<FromGitter> <straight-shoota> Unless you're using an embedded database, you're still connecting somewhere
<FromGitter> <drum445> The underlying lib usually deals with reconnects
<FromGitter> <j8r> @drum445 you know, you can use `class_getter`
<FromGitter> <drum445> ha, not sure why I didn't use them in that helper class
<FromGitter> <drum445> cheers for reminding me
<FromGitter> <straight-shoota> Okay, so you're not actually storing individual connections
<FromGitter> <j8r> what do you want for specs?
<FromGitter> <drum445> Is that helper class okay you reckon?
<FromGitter> <drum445> mongo and redis have been working fine for that for quite a few months - I have a dao layer that uses those conns
<FromGitter> <straight-shoota> Yes, that's what I meant. `DB.open "mysql://root:password@localhost/test"` creates a pool which issues a connection when you need it
<FromGitter> <straight-shoota> Regarding your original question: You could just lazily initialize these variables. So when they're not accessed (like in non-db specs) the database drivers won't be initialized
<FromGitter> <drum445> ah, cool. Thanks mate, as long as that helper class is fine.
<FromGitter> <drum445> @straight-shoota how would I do that `||=` ?
<FromGitter> <straight-shoota> yes
<FromGitter> <straight-shoota> or class_getter with a block
<FromGitter> <j8r> @drum445 `class_getter redis : Redis { some stuff } `
<FromGitter> <straight-shoota> end result is the same
<FromGitter> <drum445> How would I know I'm running tests?
<FromGitter> <drum445> a block at the top that only initailises those class vars if an env var is true or something like that?
<FromGitter> <j8r> the instance variable is initialized at the first call of the class method
f1refly has joined #crystal-lang
f1reflyylmao has quit [Ping timeout: 268 seconds]
<FromGitter> <drum445> would you mind adding that to my db helper please?
<FromGitter> <drum445> I can't quite picture that
<FromGitter> <j8r> e.g. `class_getter maria_con : DB::Database { DB.open "mysql://root:password@localhost/test" }`
<FromGitter> <drum445> Won't that be initialised as soon as the file containing that class is required?
<FromGitter> <j8r> the block will be called if `@@maria_con` is nil, which would be the case before the first call
<FromGitter> <j8r> @drum445 try with `class_getter test : String { puts "initializing"; "str" }`
Nicolab has joined #crystal-lang
<FromGitter> <drum445> ah nice, so if DBHelper.maria is never called, the db conn will never be initialised?
<FromGitter> <drum445> Is class_getter a thing in Ruby?
<FromGitter> <tenebrousedge> no
<FromGitter> <tenebrousedge> you can write something equivalent
<FromGitter> <mavu> Weird question: I have an app/service , which does things and in addition has a one page web-interface. ⏎ I need to add password protection. ⏎ I don't need user management. I don't even neccessarily need a user. ⏎ but I do need some kind of session store that remembers if the user has entered a password. ⏎ What would you (plural) do to implement that in a minimal but non-hacky way?
<FromGitter> <Blacksmoke16> cookie?
<FromGitter> <drum445> That's a shame, but thanks @j8r and @straight-shoota specs are running better now and the code looks cleaner with class_getter
<FromGitter> <Blacksmoke16> http/secure/samesite
<FromGitter> <mavu> @Blacksmoke16 could you elaborate on http/secure/samesite? A link would do, I don't understand what that means
<FromGitter> <tenebrousedge> 🍪 :D
<FromGitter> <j8r> @mavu that's exactly what we was seeking for with @tenebrousedge
<FromGitter> <Blacksmoke16> @mavu they're options for the cookie
<FromGitter> <j8r> A `HTTP::Handler` to have sessions
<FromGitter> <Blacksmoke16> secure makes it so it can only transmit over `https`, `http` means `js` cant access it, and https://crystal-lang.org/api/master/HTTP/Cookie/SameSite.html
<FromGitter> <mavu> Ohhh.. ok. cookies can have options! I see, much more comlicated creatures than I thought. ⏎ Thank you! that is a good starting point!
<FromGitter> <Blacksmoke16> also can be restricted to certain domain/path/expiration etc
<FromGitter> <mavu> Thanks, I somehow thought cookies were just key-value store on the browserside. nothing more. but apparently things are always more complex than they seem.
DTZUZU2 has joined #crystal-lang
DTZUZU has quit [Ping timeout: 272 seconds]
djuber has joined #crystal-lang
djuber has quit [Ping timeout: 240 seconds]
<FromGitter> <watzon> @straight-shoota unfortunately one of the reasons I can't use the built in documentation generation, even if the output was better, is that it only shows doc comments. For what I have in mind I need access to all comments.
Human_G33k has quit [Ping timeout: 240 seconds]
<FromGitter> <straight-shoota> Oh, that's unexpected :D what are you trying to do?
Human_G33k has joined #crystal-lang
<FromGitter> <watzon> Basically I want a lot of the features that YARD has, including the ability to make doc groups by having a start comment and an end comment where everything in between is grouped together. I can't find the documentation for it right now (ironically) but I know I've seen it several times looking through Ruby source code
Nicolab has quit [Quit: Leaving.]
<FromGitter> <Blacksmoke16> is that not the samething as doing like `# ### Some Section`?
Nicolab has joined #crystal-lang
<alexherbo2> is there an easy way to list all programs in path?
<FromGitter> <straight-shoota> Yeah, I'd like such a feature for the doc generator as well. But I would rather base it on tagging individual doc blocks, so that a section's content does not need to be grouped in lexical code
<FromGitter> <watzon> Nope. More powerful. With that way of doing things you're still at the mercy of the built in formatter, and you're forced to use markdown. But with something like: ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ *API still TBD*. But with this, you could hook into specific "groups" in your documentation template, or in the config, or elsewhere, allowing you to decide where that group gets put, how it gets
<FromGitter> <tenebrousedge> all programs in path? why?
<FromGitter> <straight-shoota> ```# A doc comment ⏎ # ⏎ # @group: api_calls ⏎ def fetch_foo(abc) ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5e4d6ea18e726c7dc5b4ef45]
<alexherbo2> implement a program launcher
<FromGitter> <watzon> @alexherbo2 do you actually want to list them, or do you want something like the `which` command?
<alexherbo2> list them
<FromGitter> <straight-shoota> @watzon If you're interested, I have a list of features I'd like to implement in the doc generator: https://notes.straight-shoota.de/YknFqORZS9urvVf7HK0nbw
<FromGitter> <tenebrousedge> I think you'd have to split `$PATH` and iterate over the segments, and check whether each file in those directories has the executable bit set
<alexherbo2> I want to list them to stdout
<alexherbo2> like dmenu_path
<FromGitter> <tenebrousedge> that's going to be a huge list
<FromGitter> <watzon> @straight-shoota I've thought of that, but I'd rather not have them have to put the group tag in every method in the group. I also want the ability to document things that are generated with macros.
<alexherbo2> will it be slow compared to built-in unix commands?
<FromGitter> <tenebrousedge> I wouldn't imagine it would be slow
<FromGitter> <straight-shoota> > I also want the ability to document things that are generated with macros. ⏎ ⏎ How's that a problem?
<FromGitter> <watzon> Well you can do that right now by writing the documentation within the macro, but that doesn't help if you want to write specific examples for different generated items. Idk, it just lacks flexibility.
<FromGitter> <watzon> There's no way right now to just write a floating doc block though afaik
<FromGitter> <straight-shoota> That's correct
<FromGitter> <straight-shoota> But that can be changed for supporting features like sections
DTZUZU2 has quit [Ping timeout: 260 seconds]
DTZUZU2 has joined #crystal-lang
<FromGitter> <DanielCoulbourne> Hey yall, quick question as a noob. I'm building a tool that uses ffmpeg for a few features. Right now it works fine since my machine has ffmpeg installed. When it comes to shipping a binary, I'm not sure what the right approach would be. ⏎ ⏎ I can think of a few options: ⏎ 1) build a C binding for ffmpeg ⏎ 2) include my own ffmpeg binary and run it from somewhere ...
<FromGitter> <Blacksmoke16> how are you using ffmpeg on your system within crystal? Assuming you have a binding setup for it?
<FromGitter> <Blacksmoke16> or just doing system calls or something?
<FromGitter> <DanielCoulbourne> right now just doing `Process.new` but I'm open to different approaches if there is a better way. This is just what I was able to get working
<FromGitter> <drum445> @j8r how would you implement class_getter in Ruby?
<FromGitter> <Blacksmoke16> afaik if you make a c binding for it (or use one already made) then you should be able to statically link your built binary to inherently include it?
<FromGitter> <Blacksmoke16> not super familiar with c binding tho, so id wait for a second opinion :p
<FromGitter> <DanielCoulbourne> Ok that's kind of how I assumed that worked. I haven't been able to find a C binding for ffmpeg thus far, so I've been procrastinating figuring out how to make one because it seems scary
<FromGitter> <DanielCoulbourne> havent written or read C in like 10 years
<FromGitter> <Blacksmoke16> https://github.com/marceloboeira/ffmpeg.cr is hella old tho
<FromGitter> <Blacksmoke16> prob fine assuming the c lib didnt change
<FromGitter> <Blacksmoke16> oh lol, its empty
<FromGitter> <Blacksmoke16> nvm
<FromGitter> <DanielCoulbourne> heh
<FromGitter> <DanielCoulbourne> That'll get you every time
<FromGitter> <DanielCoulbourne> @Blacksmoke16 Assuming you've built C-bindings before, how much of a project am I biting off for myself if I try to do this. Is this a quick afternoon's work? Or are we talking a week of evenings? (ballpark, obviously you have no way of assessing my speed)
<FromGitter> <Blacksmoke16> no idea, depends on the size of the c lib as afaik you cant just define the funs you want to use; would have to define the whole lib
<FromGitter> <Blacksmoke16> granted again, im not super familiar with c bindings so someone else might have a better idea
<FromGitter> <DanielCoulbourne> Roger. Thanks for your help anyway
<FromGitter> <Blacksmoke16> gl :p
<FromGitter> <DanielCoulbourne> The docs for C bindings could be.....
<FromGitter> <DanielCoulbourne> better
<FromGitter> <Blacksmoke16> PRs are welcomed 😉
<FromGitter> <DanielCoulbourne> haha Gotta learn how they work before I can document them ;
<FromGitter> <DanielCoulbourne> :p
<FromGitter> <kinxer> I'm confused about what you mean by "C bindings".
<FromGitter> <kinxer> You're talking about writing a C library that uses FFmpeg?
<FromGitter> <kinxer> Okay, so you just mean Crystal bindings to C.
<FromGitter> <Blacksmoke16> writing a crystal wrapper for the `ffmpeg` c lib
<FromGitter> <Blacksmoke16> yes
<FromGitter> <kinxer> Are you aware of https://github.com/crystal-lang/crystal_lib?
<FromGitter> <watzon> I started working on my own ffmpeg wrapper, but it's not ready. Still, it doesn't use C bindings. Just uses the ffmpeg CLI, so having that installed would still be necessary.
<FromGitter> <watzon> Does ffmpeg even export a C interface? I didn't think they did.
<FromGitter> <watzon> Also, this is built on top of crystal_lib and much easier to use https://github.com/olbat/libgen/
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <kinxer> Ooh. Thanks for the libgen link, @watzon. That looks useful.
<FromGitter> <kinxer> Also, I just installed the development libraries for FFmpeg4, and there are included headers.
<FromGitter> <watzon> If anyone wants to work on my library a bit though, https://github.com/watzon/ffmpeg.cr
<FromGitter> <watzon> But if there are headers included with ffmpeg it might be worth it to do a binding
DTZUZU2 has quit [Read error: Connection reset by peer]
DTZUZU2 has joined #crystal-lang
<FromGitter> <DanielCoulbourne> interesting. I'll look at all these links in a second and see if I can make sense of them. Thanks everyone
<alexherbo2> tenebrousedge do you think it should be 2 separate program for listing executables in path and run the command (could be done by the shell, but doing with the program we can store history)
<alexherbo2> I can add --option but the 2 commands are 2 total different behavior, so I think to make them separate..
<alexherbo2> how would you do?
<FromGitter> <watzon> I'd add them all to the same cli, but that's me
<alexherbo2> @watzon how?
<alexherbo2> by implementing sub-commands or just --option?
<FromGitter> <christopherzimmerman> FFMPEG does have headers, but most of the libraries I have used just make calls to the CLI. There are ways to compile ffmpeg so that you can call it as a C function rather than as a system call however.
<FromGitter> <christopherzimmerman> I would love a nice ffmpeg wrapper in crystal, I could benchmark a lot of my stuff on real-time video.
<FromGitter> <Daniel-Worrall> Is there a way to only partly statically compile?
<FromGitter> <watzon> @alexherbo2 I'd do it with subcommands. So `foo bar` rather than `foo --bar`
<FromGitter> <watzon> @christopherzimmerman majorly agree. I was making a client wrapper for it because I wanted to be able to easily write scripts for it using Crystal, and it will come in handy for recoding footage for tube type sites.
<FromGitter> <christopherzimmerman> Looking at the C code, I *think*, you could just compile with `-Dmain=ffmpeg`, and then you would be able to call `ffmpeg` as a library. I could be 100% wrong though.
<alexherbo2> @watzon do you have an example implementation?
<alexherbo2> there is nothing builtin afaik for subcommands
<FromGitter> <watzon> There are lots of libraries for handling CLIs though.
<FromGitter> <watzon> admiral, commander, and clim are all good
teardown has quit [Ping timeout: 268 seconds]
<FromGitter> <watzon> @christopherzimmerman never used `-Dmain`. What does it do?
<FromGitter> <christopherzimmerman> -D defines the value of a macro, so unless I am completely off base (which I might be), it should rename the `main` function to `ffmpeg` at compile time.
<FromGitter> <Blacksmoke16> :thinking:
<FromGitter> <Blacksmoke16> `-D` defines a compile time flag
<FromGitter> <christopherzimmerman> Hmm, the last time I used clang it had the same behavior for `-D` that gcc did, it looks like it's been removed, not sure what the equivalent is now
<FromGitter> <Blacksmoke16> oh sorry are you talking about like `crystal build -Dmain foo.cr`?
<FromGitter> <christopherzimmerman> I believe crystal's `-D` mirrors what clang does, with `gcc` it specifies a macro value
<FromGitter> <christopherzimmerman> I think I'm wrong about mirroring clang. Looks like it still matches gcc (https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-d-macro)
Nicolab has quit [Quit: Leaving.]
<FromGitter> <christopherzimmerman> Design question, does this look too clunky? I need some way of passing around the OpenCL (and cuda eventually) state information that I need, but since I can't register it globally, this just feels wrong:
<FromGitter> <christopherzimmerman> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5e4d91d6b662483a8750d92c]
<FromGitter> <christopherzimmerman> The other option is storing a reference to it on every `ClTensor`, so it's only required on allocation, and then operations will always have access to it.
<FromGitter> <watzon> Hmm, well this is only necessary if they want to pass in their own instance, right?
<FromGitter> <christopherzimmerman> No, all the time. I don't think I can initialize the library globally on start and then use that instance everywhere, as much as I would like to.
<FromGitter> <watzon> Why not? Just assign it to a class variable if it doesn't exist, no?
<FromGitter> <christopherzimmerman> Can I have a class variable that is the result of a function?
<FromGitter> <christopherzimmerman> `@@ = Cl.create_global_instance(LibCL::GPU)`?
<FromGitter> <christopherzimmerman> I thought that was checked at compile time
<FromGitter> <watzon> I'm actually not sure, but you can do something like this: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5e4d95c9d97c107ed2626b86]
<FromGitter> <watzon> The benefit of the class method is that you don't have to check for `nil`
<FromGitter> <tenebrousedge> you can do ⏎ ⏎ ```class Foo ⏎ @@bar : String ⏎ @@bar = "abc" ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5e4d95f44880f07ed1e6d3d2]
<FromGitter> <tenebrousedge> but having an accessor method is probably going to be useful
<FromGitter> <watzon> You may also be able to do `class_getter! instance : Cl::GPU = nil`
<FromGitter> <watzon> That will add a method `instance!` which automatically calls `not_nil!` I believe
<alexherbo2> @watzon between the 3, is there one you suggest me?
<alexherbo2> I'm looking at their readme but I can't decide which one to go
<FromGitter> <Blacksmoke16> `class_getter instance : Cl::GPU { Cl.create_global_instance(LibCL::GPU) }`
<FromGitter> <Blacksmoke16> lazily set the value
<FromGitter> <watzon> @alexherbo2 for your purposes I'd go with commander
<alexherbo2> what are the difference between them?
<FromGitter> <watzon> @Blacksmoke16 that's not a bad idea. Didn't know you could do that actually.
<alexherbo2> commander looks easy to setup yeah
<FromGitter> <christopherzimmerman> Is that only evaluated once?
<alexherbo2> just def and bam
<FromGitter> <watzon> @alexherbo2 really just the interface
<FromGitter> <watzon> Commander is the simlest to set up I think
<alexherbo2> you have code using them?
<FromGitter> <watzon> I don't think I have anything public that's using them
<FromGitter> <watzon> Damn
<FromGitter> <watzon> I feel like I learn something new every day from @Blacksmoke16
ur5us has joined #crystal-lang
<alexherbo2> you split one command in their own file or put everything in the main?
<FromGitter> <christopherzimmerman> Can confirm it is only evaluated once, that's nifty, definitely using that.
<FromGitter> <watzon> @alexherbo2 the main reason I suggested commander is because you can just put everything together easily and don't have to deal with each command being its own class. Your use case I think is pretty simple, no need to split things up.
<alexherbo2> admiral looks simpler no?
<FromGitter> <watzon> Nah, every command in admiral is its own class
<FromGitter> <watzon> Lots more to write
<alexherbo2> class in class looks strange
<alexherbo2> @watzon https://github.com/basecamp/sub
<FromGitter> <watzon> Not a big fan
Nicolab has joined #crystal-lang
<FromGitter> <watzon> If I have a macro inside of a class, and I want that macro to be able to add methods to that class from outside of the class. Is there a good way to do that?
<FromGitter> <watzon> Back to my middleware shit, I decided to make the `use` method into a macro instead, thinking that this would evaluate it all at compile time and allow me to add methods to the `MiddlewareRegistry` module where the `use` macro is being defined.
<FromGitter> <Blacksmoke16> :thinking:
<FromGitter> <Blacksmoke16> whats the benefit of that versus just auto registering everything to the registry?
<FromGitter> <Blacksmoke16> then picking the middleware it should use
<FromGitter> <Blacksmoke16> in regards to your question, i would need to see an example, not sure i totally follow
<FromGitter> <watzon> Hmm that might work, I still don't know how I'm going to get the `@[Export]` annotated methods into the client though
<FromGitter> <Blacksmoke16> would have to have the middleware have a parent type or module that you can iterate over
<FromGitter> <watzon> Hmm ok
<FromGitter> <Blacksmoke16> granted idk the actual implementation you have going to know if that would be useful or not
<FromGitter> <watzon> Would the `finished` macro be a good place to iterate over subclasses of the `Middleware` class to register them all?
<FromGitter> <Blacksmoke16> where would that finish macro live?
<FromGitter> <watzon> Inside of the `MiddlewareRegistry` module or the `Middleware` abstract class probably
<FromGitter> <watzon> Idk which would be better
<FromGitter> <Blacksmoke16> that would prob work
<FromGitter> <watzon> Really if I do things this way I don't know if I'll need the former
<FromGitter> <watzon> Since the whole point of that module was to register middleware
<FromGitter> <Blacksmoke16> if the abstract class is intended to be an interface id maybe put it there?
<FromGitter> <watzon> Yeah it is. Probably the best place.
<FromGitter> <Blacksmoke16> or may i also consider making the interface as a module
<FromGitter> <Blacksmoke16> and the abstract class be an implementation of that module
<FromGitter> <Blacksmoke16> suggest*
<FromGitter> <watzon> Not sure if I follow
<FromGitter> <Blacksmoke16> like does the abstract class have logic in it, or just `abstract def xxx`?
<FromGitter> <watzon> Mainly it just has defs. Tbh I'm not even using `abstract `def`s right now, because I want the `init` and `call` methods to be optional.
<FromGitter> <watzon> But for now there's no logic in there
<FromGitter> <Blacksmoke16> thats fair
<FromGitter> <Blacksmoke16> then my actual type includes that module
<FromGitter> <Blacksmoke16> and all the types use the interface
<FromGitter> <watzon> Ahh so basically I'd have a `Middeware` module, and then custom middleware would just include that module?
<FromGitter> <Blacksmoke16> doesnt interfere with inheritance and doesnt lock an implementation to `class` or `struct`
<FromGitter> <watzon> And then the `Middleware` module itself could register classes that include it
<FromGitter> <watzon> I like that idea actually
<FromGitter> <Blacksmoke16> `MiddlewareInterface` to make it clearer, since we dont really have actual interfaces
<FromGitter> <watzon> Unfortunately. I like modules, but there's a few things they just can't do that real interfaces can.
<FromGitter> <watzon> But I like this idea
<FromGitter> <Blacksmoke16> ofc, abstract protected methods, or abstract static methods etc
<FromGitter> <Blacksmoke16> but is the most interface like thing we have atm, and probably be easier to update to use actual interfaces if they ever become a thing
<FromGitter> <Blacksmoke16> compared to an inheritance approach
<FromGitter> <watzon> True
<FromGitter> <Blacksmoke16> `implement MiddlewareInterface` versus `include MiddlewareInterface` idk
<FromGitter> <watzon> Crap, I forgot how to use a class definition as a Hash key
<FromGitter> <Blacksmoke16> `Type.class`
<FromGitter> <watzon> Ahh yeah
<FromGitter> <watzon> I tried to go generic with `Class.class` but was getting an error
<FromGitter> <Blacksmoke16> heh yea that wouldnt work
<FromGitter> <watzon> Wasn't sure if `MiddlewareInterface.class` would work, but it does
<FromGitter> <Blacksmoke16> mhm
<FromGitter> <Blacksmoke16> long as you dont introduce generics into it
<FromGitter> <Blacksmoke16> doesnt work well ha
alexherbo29 has joined #crystal-lang
alexherbo2 has quit [Ping timeout: 240 seconds]
alexherbo2 has joined #crystal-lang
alexherbo29 has quit [Ping timeout: 260 seconds]
<FromGitter> <straight-shoota> @paulcsmith Did you see my comment immediately above yours? https://github.com/crystal-lang/crystal/issues/5874#issuecomment-588472157 Having only compile-time configuration is simply not an option to consider.
<FromGitter> <paulcsmith> @straight-shoota Yes just responded. I wasn't suggesting only compile-time configuration. It was all runtime
<FromGitter> <paulcsmith> I'm just saying that you can get type-safety by using code and not YAML. You will get a nice error at compile time if you try to use a backend that doesn't exist, typoed, arguments, etc. This is what we do in Lucky with Habitat. It's all using Crystal and all options are safe at compile time: https://github.com/luckyframework/habitat
<FromGitter> <paulcsmith> For example, here is configuring or logger at Runtime and using conditionals to handle different paths https://github.com/luckyframework/lucky_cli/blob/master/src/web_app_skeleton/config/logger.cr#L3-L30
<FromGitter> <paulcsmith> Another very cool example, is using a Proc when configuring a logger to skip certain requests, this is simply not possible with YAML: https://github.com/luckyframework/lucky_cli/blob/3554155be1790d15d4c94719c8d5a3ada8312718/src/web_app_skeleton/config/logger.cr#L38-L43
<FromGitter> <paulcsmith> I love the direction of the logger in that it uses `Log` everywhere, the context is awesome, etc. But using YAML doesn't give additional features over doing it in Crystal, but doing it in Crystal means better docs, better errors, and much more flexibility (use procs, env vars, conditionals, etc)
<FromGitter> <paulcsmith> And I know it works because we've been using it for awhile and have done some pretty cool stuff with it as linked above ^
<FromGitter> <paulcsmith> Another example, what if you need a password for a backend, such as ElasticSearch where it needs a URL that you don't want to check in to code. How would you do that with YAML? You could encrypt the YAML file but that introduces a bunch of other issues to solve. If using Crystal code, you can use ENV and access it no problem. So I think there are tons of benefits to be had by using Crystal
<FromGitter> <Blacksmoke16> @paulcsmith https://github.com/crystal-lang/crystal/issues/8598
<FromGitter> <Blacksmoke16> would allow you to do that
<FromGitter> <paulcsmith> It would allow some things yes, but not all. Procs for example are not possible. Conditionals are trickier, and there is still fewer compile-time guarantess. For example if done in Crystal: `Log.formatter = MyFormater` I would get a nice compile time error pointing to the exact line and position along with a helpful "Did you mean MyFormatter?".
<FromGitter> <paulcsmith> I'm curious what YAML gives us that Crystal code does not. So far I see things that it takes away and don't see anything it gives us. But maybe I am missing a use case. Would love to learn more about why people prefer it
<FromGitter> <straight-shoota> You're missing the major difference: changing `Log.formatter = MyFormatter` needs a rebuild. Changing `formatter: myformatter` in a YAML file (or whatever config format) does not.
<FromGitter> <paulcsmith> It does require a restart, but yes changing `Log.formatter = MyFormatter` would require a rebuild. I'll leave a comment in the thread, but I think there are *many* teams that would consider being able to change any configuration in production at runtime to be a very dangerous practice
<FromGitter> <paulcsmith> If people want to do that, it is fine, but I would be in support of a separate shard that people can use if they want to do that. If you want to configure specific parts of config then you can code in those parts with ENV vars or reading from a YAML file for just those parts
<FromGitter> <tenebrousedge> I mean, I'd be interested to hear a case where that was sensible
<FromGitter> <straight-shoota> This might not matter so much for your typical Lucky application because developer and operator are typically the same and has no issue with configuring the application at compile time.
<FromGitter> <paulcsmith> I dunno. I've worked on large teams and no one has ever wanted or suggested being able to change all config at runtime. If anything I think they'd get significant pushback on that. Seems extremely dangerous to be editing yaml files on a running server
<FromGitter> <straight-shoota> But think more widely about typical systems software which is distributed through package managers. The package maintainers usually provide a default config and users can adopt that to their needs. This workflow must not require a rebuild (which would depend on a Crystal toolchain available and take time + resources).
<FromGitter> <straight-shoota> Crystal applications are not just web servers.
<FromGitter> <Blacksmoke16> fwiw the editing of the yaml file can be more than just `vi`
<FromGitter> <tenebrousedge> okay but couldn't you support different log levels without a rebuild, just not arbitrary rejiggering of the loggin?
<FromGitter> <Blacksmoke16> afaik there are some configuration tools out there that would handle doing it, i.e. prob validating input etc before writing
<FromGitter> <straight-shoota> I do totally understand that for some use cases you want to avoid such runtime configuration for security reasons. That's totally fine. It just means not compiling the config parser. Done. Leaving that out is easy. But the other way would be hard or impossible, if we design the system for applications that don't need/want runtime configuration.
<FromGitter> <paulcsmith> @straight-shoota I don't think so. I think people can read from YAML in their code with little issue. Example in a sec
<FromGitter> <paulcsmith> https://gist.github.com
<FromGitter> <paulcsmith> Oops :)
<FromGitter> <paulcsmith> My main point is this. Crystal is way more flexible, can allow just about *anything* including using YAML, env vars, etc. Whereas if we built in YAML from the start and design the logger around that we lose a LOT. Better documentation, better compile time errors (for those not using env vars/yaml), more flexibility with conditionals, procs, etc
<FromGitter> <straight-shoota> I don't follow. How's that supposed to show anything remotely similar to the complexity of, say the configuration example by bcardiff in https://github.com/crystal-lang/crystal/issues/5874#issuecomment-587090645 ?
<FromGitter> <paulcsmith> For complex cases, my suggested approach would work, but would be a bit more annoying. However, someone could make a shard for YAML -> Crystal. @Blacksmoke16 mentioned such stuff here: https://github.com/crystal-lang/crystal/issues/8598.
<FromGitter> <straight-shoota> Also, I disagree with all your conclusions. Documentation doesn't need to be worse. There'll obviously be compile time errors when using the Crystal API.
<FromGitter> <paulcsmith> It is a fact documentation will be worse. Because methods with args and strict types *will* have better documentation. It will be searchable, it'll show the types, etc. If you don't do that then you need to document it yourself. Right? Or maybe there is something I'm missing
<FromGitter> <watzon> Is there a way with macros to see if a class includes a module?
<FromGitter> <paulcsmith> > There'll obviously be compile time errors when using the Crystal API ⏎ ⏎ I'm not sure I follow? I've shown examples of how using a code first approach can show better compile time errors
<FromGitter> <watzon> There's the opposite in `TypeVar#includers`
<FromGitter> <paulcsmith> But another important part is that even if the Log supports YAML by default, we would need a library of some sort to make this easier for other configuration. People don't just configure loggers
<FromGitter> <paulcsmith> Which is why I think a separate shard for configuration with YAML makes sense. It would be much more flexible and allow for configuring all kinds of Crystal code with YAML. Then you'd keep the logger using regular Crystal methods and arguments and wold benefit from better errors, docs, etc. and for those not using YAML you'd be able to do excellent stuff with conditionals, procs, etc. that are *impossible*
<FromGitter> ... to do with YAML
Nicolab has quit [Quit: Leaving.]
<FromGitter> <straight-shoota> > Because methods with args and strict types will have better documentation. ⏎ ⏎ Who says they won't be there?
<FromGitter> <straight-shoota> In fact there hasn't been any talk about the internal configuration API at all. I guess you're just assuming something about it.
<FromGitter> <straight-shoota> Maybe it would help you see the scope when looking at examples of other logging solutions. logging.properties (https://github.com/search?utf8=%E2%9C%93&q=filename%3Alogging.properties&type=Code) for example is a typical configuration file for Java's java.logging library.
<FromGitter> <watzon> > Is there a way with macros to see if a class includes a module? ⏎ @Blacksmoke16 any idea? ⏎ ⏎ I'm trying this right now: ⏎ ... [https://gitter.im/crystal-lang/crystal?at=5e4db39e3ca8a67fb8069013]
<FromGitter> <paulcsmith> @straight-shoota The internal configuration was talked about at the bottom. It showed the type signatures for backend config and it is hashes with a few simple types. Brian mentioned it further down as well that you'd have to handle validation of the config at runtime
<FromGitter> <paulcsmith> I'd love to see `max_file_size : Int32`, not `ConfigOptions : Hash(String, BunchOfOtherValues)`
<FromGitter> <paulcsmith> One has much better compile time guarantees, and better documentation
<FromGitter> <paulcsmith> As I said, the only reason to have ConfigOptions like that is because it is designed to read from something outside Crystal. I think that type of config should be a separate shard for all the reasons I state above. Better documentation, better compile time guarantees, more flexibility. Plus if its a shard for loading config with YAML, you could use it with code outside of Crystal's logger. Total win-win I
<FromGitter> ... think
djuber has joined #crystal-lang
<FromGitter> <paulcsmith> I appreciate you talking this through with me. I had not thought about people wanting to configuring binaries with YAML for example. That is a use-case I hadn't thought of! I do get a little focused on web sometimes :)
<FromGitter> <straight-shoota> The illustrated types are meant to illustrate the structure. It is explicitly stated that it's not the actual definition.
<FromGitter> <straight-shoota> For example, a fully flexible model could be implemented being backed by a `Hash` (so you can load in any data from a config file) but it exposes a Crystal API that offers type safety. Obviously that safety can't be guaranteed if you're mixing the strict API with externally sourced values. But as long as you're only using the API, this could be totally type safe while offering the necessary flexibilty.
jhass has left #crystal-lang [#crystal-lang]
jhass has joined #crystal-lang
<FromGitter> <watzon> Hmm. `Error: no overload matches 'Array(Tourmaline::MiddlewareInterface:Module)#[]=' with types Tourmaline::CallbackQueryMiddleware.class, Tourmaline::CallbackQueryMiddleware.class`
<FromGitter> <watzon> `CallbackQueryMiddleware` includes `MiddlewareInterface`, so this should work, should it not?
<FromGitter> <straight-shoota> `Tourmaline::CallbackQueryMiddleware.class` is a class type, can't be an instance of `MiddlewareInterface`
<FromGitter> <Blacksmoke16> @watzon not that i can think of atm
<FromGitter> <Blacksmoke16> @paulcsmith @straight-shoota https://github.com/crystal-lang/crystal/issues/5874#issuecomment-587167789 was the thought i had on this
<FromGitter> <Blacksmoke16> should be possible to use `from_yaml`, in which case might not actually need the config `YAML::Any` like type
<FromGitter> <Blacksmoke16> heres a question, been thinking about the rework of my validation shard, mainly the API/interfaces im going to use for it
<FromGitter> <Blacksmoke16> the idea is the `validate` method would return the validations that failed
<FromGitter> <Blacksmoke16> the question is, should that be `Array(ConstraintViolationInterface)` or its own type like `ConstraintViolationListInterface` that essentially wraps the array and provides helper methods like `def add(violation : ConstraintViolationInterface)`
<FromGitter> <Blacksmoke16> where ofc the list type would include `Indexable`
<FromGitter> <Blacksmoke16> leaning towards just the array, am doubting the wrapping type would be an improvement
<FromGitter> <Blacksmoke16> ```list.add violation ⏎ vs ⏎ list << violation``` [https://gitter.im/crystal-lang/crystal?at=5e4dc8cea0aa6629f5dccf79]
<FromGitter> <RyanScottLewis> I may have found a bug with `expand_path`: `/home/user/tmp/test.cr` contains `puts File.expand_path("~/crystal/foo")` and returns `/home/user/tmp/~/crystal/foo`
<FromGitter> <tenebrousedge> doesn't it have a second arg?
<FromGitter> <tenebrousedge> that handles whether `~` is expanded?
<FromGitter> <RyanScottLewis> Doesn't seem to matter where the source is or if it's compiled. It prepends the pwd onto the resulting path and doesnt expand the tilde
<FromGitter> <Blacksmoke16> `, home: true`
<FromGitter> <RyanScottLewis> I must be looking at old documentation
<FromGitter> <Blacksmoke16> `puts File.expand_path("~/crystal/foo", home: true)`
<FromGitter> <straight-shoota> Not a bug, see #8797
<DeBot> https://github.com/crystal-lang/crystal/issues/8797 (File.expand_path broken - ~ (tilde) not replaced correctly)
<FromGitter> <RyanScottLewis> Okay phew I thought I was going crazy
<FromGitter> <straight-shoota> Home expansion is opt-in since 0.32.0
DTZUZU has joined #crystal-lang
DTZUZU2 has quit [Ping timeout: 260 seconds]
ur5us has quit [Ping timeout: 240 seconds]
<FromGitter> <watzon> Is there a way to iterate over an enum's items with a macro?
<FromGitter> <Blacksmoke16> pretty sure you can do `.constants`
<FromGitter> <watzon> Ahh yeah, that makes sense