<FromGitter>
<watzon> I find that searching `language:crystal search-term` on github works really well. Hopefully crystalshards will support gitlab in the not too distant future too.
<straight-shoota>
watzon, shardbox already does
<FromGitter>
<watzon> Well it supports it, but shardbox requires manual insertion doesn't it? It doesn't index.
<straight-shoota>
it doesn't care where a shard is hosted, as long as `shards install` can find it
<straight-shoota>
For now it doesn't have full autodiscovery, yes.
<FromGitter>
<watzon> Is that planned?
<FromGitter>
<watzon> Also is it planned to make shardbox official? I saw a comment on a post in the Ruby subreddit yesterday that mentioned difficulty in finding a place where shards are listed because shardbox isn't linked to on the crystal-lang homepage. I made sure to tell them that that's because shardbox isn't official for now.
<straight-shoota>
Technically, it's super simple. GitHub discovery is more or less already implemented, GitLab etc. should be fairly easy to do. I'm not sure it's a good idea though to list every single repository with a shard.yml
<straight-shoota>
if that's your definition of official, the it is =)
<FromGitter>
<watzon> I think there should be some requirement for indexing so you can explicitly make sure your project is indexed. Were it just github you could look for a topic `crystal-lang` or something, but it's not. It could be possible to have a section in `shard.yml` or something, or only check for projects that have releases.
<FromGitter>
<watzon> Didn't know there was a link on the community page. I'll have to update my answer on reddit.
<FromGitter>
<watzon> Personally I'm not a fan of that approach. It requires a PR and it's just another thing to maintain on top of any projects you're working on. Like I moved my `tourmaline` project to the `protoncr` org a bit ago, but I haven't gone in and updated it yet.
<FromGitter>
<watzon> Guess I better do that
<straight-shoota>
The implementation of GitHub discovery is actually for a tool to make adding uncataloged shards from GutHub easy
<straight-shoota>
Blacksmoke16 +1
<straight-shoota>
watzon, I fully understand your concerns
<straight-shoota>
But I don't think there's a better way to manage such a catalog than as a git repo
<straight-shoota>
Having a simple tool for adding new shards to the catalog would certainly help the process
<FromGitter>
<watzon> For sure. If shardbox is going to be the official tool it would be nice if shards would do that.
<FromGitter>
<watzon> I just got Tourmaline updated in the catalog though
Nekka has quit [Ping timeout: 272 seconds]
<straight-shoota>
Great
<straight-shoota>
you only need to add description and mirrors once
<straight-shoota>
not in every category
<straight-shoota>
the formatter check will complain about that :D
<straight-shoota>
just another example why it's not super user friendly^^
<FromGitter>
<watzon> Ahh ok, I was just keeping more or less with what was there before
<FromGitter>
<watzon> But yes haha
<FromGitter>
<watzon> So I should just have `- github: protoncr/tourmaline` in one of the categories?
<FromGitter>
<watzon> And then have everything in the other?
<straight-shoota>
exactly
Nekka has joined #crystal-lang
<FromGitter>
<watzon> I know that I know the answer to this, but it's been a long day and I'm spacing
<FromGitter>
<watzon> What would be the best way to convert a string to binary representation?
<FromGitter>
<Blacksmoke16> .to_s 2
<FromGitter>
<watzon> That's for integers haha
<FromGitter>
<3n-k1> loop through each character of the string and bitshift to get the representation of each bit? i'm not sure of any other way to do it
<FromGitter>
<3n-k1> that doesn't sound like fun with unicode though
<FromGitter>
<watzon> I guess I just have to use `IO::ByteFormat::LittleEndian.decode` on each byte and then convert that to a binary string
<FromGitter>
<watzon> Thought I remembered there being an easier way, but I guess not
<FromGitter>
<Blacksmoke16> :thinking:
<FromGitter>
<Blacksmoke16> does it have to be binary, or just the bytes?
<FromGitter>
<watzon> I want the binary representation, the bytes are easy
<FromGitter>
<watzon> Hmm interesting. Cold probably have some performance penalties for larger strings as compared to using IO::ByteFormat, couldn't it?
<FromGitter>
<Blacksmoke16> true, i suppose it would prob be easy to get over that if you use a large enough string
<FromGitter>
<watzon> Well that's certainly a way to do it haha
<FromGitter>
<watzon> Probably the most efficient, though definitely not the most pretty
<FromGitter>
<3n-k1> i've had c pounded into me and now i just see strings as integer arrays lmao
deavmi has quit [Ping timeout: 272 seconds]
deavmi has joined #crystal-lang
<FromGitter>
<watzon> 76/4
straight-shoota has quit [Ping timeout: 246 seconds]
rocx has left #crystal-lang ["👏 developers 👏 developers 👏 developers 👏 developers 👏 developers"]
return0e_ has joined #crystal-lang
return0e has quit [Ping timeout: 256 seconds]
rocx has joined #crystal-lang
rocx has quit [Ping timeout: 260 seconds]
_ht has joined #crystal-lang
zorp has joined #crystal-lang
Nekka has quit [Ping timeout: 260 seconds]
Nekka has joined #crystal-lang
wakatara has joined #crystal-lang
_ht has quit [Remote host closed the connection]
_ht has joined #crystal-lang
return0e has joined #crystal-lang
return0e_ has quit [Read error: Connection reset by peer]
<FromGitter>
<neutrinog> why can't I do this? ⏎ ⏎ ```class MyClass(T) ⏎ @@stuff = Hash(String, T).new ⏎ end``` ⏎ ⏎ I get a compile error `can't infer the type parameter T for the generic class MyClass(T). Please provide it explicitly ... [https://gitter.im/crystal-lang/crystal?at=5eb3a6e59f0c955d7dac376d]
<oprypin>
jhass: can i pretty please get a plaintext field to put code in on carc.in? i quite literally can't use it on mobile https://i.imgur.com/zc8EiNw.jpg
sz0 has quit [Quit: Connection closed for inactivity]
<oprypin>
neutrinog, i guess the `initialize` needs to refer to the T in some way
<oprypin>
ah lol this is a class variable. never thought of that use case. well yeah, this is just one global variable same for all instances, there's no feature to create them on the fly somehow per instantiation of a generic
<FromGitter>
<neutrinog> yeah I was playing around with generic singletons.
<FromGitter>
<neutrinog> I guess it's not possible.
<oprypin>
maybe it should be. c# does it apparently
<FromGitter>
<neutrinog> I'm trying to get around the fact that class variables are not the same for subclases. It might be hard to explain without an example, but basically you can get around that by using a class variable that itself is a singleton.
<FromGitter>
<neutrinog> But then you have to create a bunch of singletons. Hence my attempt at a generic singleton.
<oprypin>
also... have you considered, like, relying on actual garbage collection
<FromGitter>
<neutrinog> I am actually. All I'm doing for the garbage collection is removing items from a hash once all their references are gone. Then I rely on `finally` to do the clean up.
<oprypin>
but you dont need to remove anything
<FromGitter>
<neutrinog> The important part I'm implementing is the reference counter so I can avoid loading resource more than once.
<oprypin>
once all references are gone, it *is* garbage collected
<FromGitter>
<neutrinog> One potential problem here, I'm not sure how much of a problem it will be in my case. If I have a hash of weak references, my hash will simply grow
<oprypin>
or populate that array with User.new.as(Model) in the first place
<FromGitter>
<neutrinog> I'm not sure I want to search through the dictionary every time a method is called.
<FromGitter>
<Whaxion> Thanks @oprypin it works perfectly 😄
<FromGitter>
<neutrinog> @oprypin here's my final pool implementation with weak references. https://carc.in/#/r/90uy
<oprypin>
@neutrinog: mmmmm that's iterating over everything on every address
<oprypin>
access*
<FromGitter>
<neutrinog> yeah that's the python code was doing as well. At least that was my understanding. It's been awhile since I had to write python.
<oprypin>
no no it's not
<oprypin>
it iterates over a list that only has items marked to be deleted
<oprypin>
tbh at this point i think your idea with reference counting is easier
<FromGitter>
<neutrinog> yeah I'll stick with that for now. No looping required. And I guess I'm stuck with writing some boiler plate singletons for now until we get generic class variables (if we get them)
<FromGitter>
<neutrinog> ah.. but I forgot about the macros again. I can probably create a reasonably clean solution now.
<oprypin>
neutrinog: i just realized, this is just doing generics the Go way. can't be bad, right?
<oprypin>
😩😂
straight-shoota has joined #crystal-lang
<FromGitter>
<waghanza> hi, is this ok to build an app on *alpine* (with `musl`), but to run it on *linux* (with `glibc`) ?
<raz>
if it's a static build then i would say yes
<raz>
(i think that's what alpine/musl is commonly used for - build static binary, deploy anywhere)
rocx has joined #crystal-lang
<straight-shoota>
Yes, that's the purpose of static linking. You don't need to care what libraries are available in the runtime system, everything is included in the executable
<FromGitter>
<waghanza> ok, ❤️
<FromGitter>
<Afront> Can I use Process.run inside a spawn block? I tried it and it soft crashes after it tries running the process.
<straight-shoota>
Afront, yes that should work without issues
<straight-shoota>
can you share your code?
<straight-shoota>
A common reason for unexpected failure is that the main fiber exits.
<jhass>
I see straight-shoota got converted to IRC :D
<straight-shoota>
Then the program will exit and stop all spawend fibers
<straight-shoota>
haha, I'm trying
<FromGitter>
<Afront> Oh thanks @straight-shoota, that was the problem. I didn't put sleep after `yield`ing the main fiber.
<FromGitter>
<Afront> It works now, thanks!
<jhass>
why don't you run the process in the main fiber if it has nothing else to do?
<FromGitter>
<hugopl> but why the syntax sugar doesn't work?
<FromGitter>
<hugopl> is there a reason?
<FromGitter>
<Blacksmoke16> parser prob just not taking the `@` into account, maybe search github and see if theres an issue for it already
<FromGitter>
<hugopl> yeah, I was looking for that just now, and found none
<FromGitter>
<hugopl> I'm going to search a bit more... then create the issue if I find none
<FromGitter>
<Blacksmoke16> 👍
<FromGitter>
<neutrinog> hey, I created a macro. It's in one file, and I'm using it in another. I've imported the macro file but I'm getting an error `Error: macro 'your_macro_name' must be defined before this point but is defined later`
<FromGitter>
<neutrinog> any ideas?
<FromGitter>
<Blacksmoke16> make sure you require it before you use it?
<FromGitter>
<neutrinog> yep. Imported at the top of the file.
<FromGitter>
<Blacksmoke16> not using it anywhere else?
<FromGitter>
<neutrinog> in the specs
<FromGitter>
<neutrinog> hm.. deleted the specs temporarily and got this error. `undefined method...`
<FromGitter>
<Blacksmoke16> :thinking: hard to say without seeing the code
<FromGitter>
<Blacksmoke16> pretty sure it has to be some require order issue tho
<FromGitter>
<neutrinog> yeah. it's a big project..hmm.
<FromGitter>
<neutrinog> ok maybe this is not ideal but here's a screenshot.
<FromGitter>
<neutrinog> The two files are open on the right, the error is below. You can see the relative folder location on the left.
<FromGitter>
<Blacksmoke16> maybe try adding `--error-trace` and see if that adds anything useful
<FromGitter>
<neutrinog> hmm.. not much. I'm running `crystal spec`. So I see call tree and it fails when importing the core library. it's standard for the root file in a library to simply call `require "./mylib/*"` right?
<FromGitter>
<Blacksmoke16> ehh i usually run into require issues when doing that
<FromGitter>
<Blacksmoke16> its afaik its required in ABC order, so if the macro was defined in a `m` file, but used in an `b` file, then you have to manually require `m` within `b`
<FromGitter>
<neutrinog> sure, but the manual import does not seem to work.
dostoyevsky has quit [Quit: leaving]
dostoyevsky has joined #crystal-lang
<FromGitter>
<neutrinog> hm... so if I use `extend self` in the module in my macro file I properly access the macro without problems using it like a method of the module.
<FromGitter>
<neutrinog> I think the error message may be misleading because it can clearly find the import.
<FromGitter>
<neutrinog> I don't even need the manual import now.
<FromGitter>
<Blacksmoke16> nice
postmodern has quit [Quit: Leaving]
<FromGitter>
<neutrinog> oh.. so I don't need to extend the module at all. This is so strange. The two files have the same namespace so it doesn't make sense why i need to specify when calling the macro.
<FromGitter>
<neutrinog> ok so this is my solution. The macro generates a particular class so I nested it inside there so I can simply call it like `ReferencePool.create_persistent_pool(Texture)`. This seems to work in all cases. I still don't understand why it didn't initially work, but at least this solution doesn't look hacky.
<oprypin>
@neutrinog: if you have even one asterisk inside a require in your project, all bets are off
<FromGitter>
<neutrinog> lol. So what do you suggestion? Just manually importing everything. I'm too lazy. :P
<FromGitter>
<neutrinog> But seriously, what's the standard?
<FromGitter>
<Blacksmoke16> or at least have file that requires related files, then you main file just requires all those specific "index" files?
<FromGitter>
<j8r> IMO `require "**"` is bad design decision
<FromGitter>
<j8r> double wildcards in requires
<FromGitter>
<j8r> simple wildcard is easy enough
<FromGitter>
<neutrinog> ok so maybe at most use a single wildcard at the top of the lib and then next things below in folders. Following suit as needed.
<oprypin>
@neutrinog: yes that's how everyone else does it in every other programming language
<FromGitter>
<j8r> using double leads to unwanting
<FromGitter>
<j8r> ... effects
<oprypin>
expect Ruby but. ..
<FromGitter>
<j8r> @neutrinog yep, require only what is needed
<oprypin>
single is also unpredictable
<FromGitter>
<j8r> yep oprypin, but better
<FromGitter>
<j8r> sometimes not that much, if there are only few files
<FromGitter>
<Blacksmoke16> i only use `*` when its a dir that are just implementations of the same interface/or all realted
<FromGitter>
<Blacksmoke16> like `require "./events/*"` where that is like `AbstractEvent`, `SomeEvent`, `AnotherEvent` etrc
<FromGitter>
<neutrinog> ok, for some reason I thought `crystal init` generated the root file with the double wildcards. So I thought that was the standard, however the last time I init'd a project was 2 years ago.
<jhass>
pretty much, UpperCamelCase to lower_underscore_case
Human_G33k has joined #crystal-lang
HumanGeek has quit [Ping timeout: 272 seconds]
return0e_ has joined #crystal-lang
renich has quit [Ping timeout: 264 seconds]
return0e has quit [Ping timeout: 264 seconds]
beepdog has quit [Quit: Idle for 30+ days]
<raz>
i think wildcard is nice to have. there's few cases where it's useful (due to the non-guaranteed import order), but it's in these cases it's a nice convenience (and imho clearer at a glance than the ruby contraption)
<FromGitter>
<UnsolvedCypher_gitlab> For using the Crystal VSCode extension, do most people here use scry or just the default language server?
<FromGitter>
<watzon> I don't bother with scry most of the time
<FromGitter>
<watzon> Doesn't work very well as is
<FromGitter>
<UnsolvedCypher_gitlab> Alright, it looks like the built-in autocompletion works well enough anyways. Thanks @watzon!
<FromGitter>
<neutrinog> is it possible to pass a captured block to a macro?
<FromGitter>
<neutrinog> e.g. `my_macro("arg") do {...}`
<FromGitter>
<watzon> Macros can have a block if that's what you mean
<FromGitter>
<neutrinog> I mean what's the syntax for accepting a callback to a macro.
<FromGitter>
<neutrinog> I'm trying to generate a method that accepts a callback, but I want to define the callback when I call the macro.
<FromGitter>
<watzon> Same as with a normal method I believe
<FromGitter>
<neutrinog> I just mean prototyping with the local playground is misleading if it's not giving you the proper textual output on the side.
<FromGitter>
<watzon> Idk what you mean
<FromGitter>
<neutrinog> I was confused for awhile why my code wasn't working when in fact it was. The playground just wasn't logging all of the print statements.
<FromGitter>
<watzon> Well it's logging the ones that are actually being called
<hightower2>
thankfully also the docs for sam became better lately
hightower2 has quit [Ping timeout: 260 seconds]
hightower2 has joined #crystal-lang
sagax has quit [Ping timeout: 260 seconds]
<FromGitter>
<watzon> There's no way to pause a fiber is there?
<FromGitter>
<watzon> Seems like they have the ability to resume, but not pause
zorp has quit [Ping timeout: 256 seconds]
<FromGitter>
<bew> Pause, by the fiber? Or from another fiber? Until resume? Or to let other fiber run in the mean time?
<FromGitter>
<watzon> Pause from another fiber. I know I'm thinking about this the wrong way, but I'm trying to find out how to do what Ruby's `Thread` can do.
<Sharcho>
Is there a build time option to disable multithreading?
<FromGitter>
<Blacksmoke16> it's disabled by default so no option needed
<FromGitter>
<Blacksmoke16> its opt in not opt out
<Sharcho>
When I do ps on a crystal process, it shows 8 threads
<Sharcho>
ps -e -T | grep mycrystalapp
<FromGitter>
<Blacksmoke16> mmm
<FromGitter>
<Blacksmoke16> whats the process? just like `puts "hello world"`?
<Sharcho>
more or less, with a sleep in it
<FromGitter>
<Blacksmoke16> could be internal stuff, a bit outside of my area of expertise tho
<FromGitter>
<Blacksmoke16> like the event loop and such
<Sharcho>
It happens with a program that contains only "sleep 1000", and crystal build --release
lanodan has quit [Ping timeout: 265 seconds]
<hightower2>
Hey quick one about crecto, after i Repo.insert(obj), how do I get obj.id to actually be populated with the assigned DB id?
<FromGitter>
<Blacksmoke16> :shrug: i thought that repo was abandoned
<hightower2>
in favor of Repo::Query or?
_ht has quit [Remote host closed the connection]
<hightower2>
actually no, query is query... looking at official docs there's no note of not using Repo
<FromGitter>
<Blacksmoke16> no i mean the library itself. Last i heard it was no longer maintained
<FromGitter>
<Blacksmoke16> guess its back now
<hightower2>
interesting, I used it after someone praised its completeness here week or two ago, and the last commit is from a day or two ago
<FromGitter>
<watzon> I'd recommend clear or granite personally
<hightower2>
after completing a basic model with it, I am not too happy, would have used something else probably, but wel...
<FromGitter>
<watzon> As an ORM
<FromGitter>
<Blacksmoke16> hows your ORM going? :p
<FromGitter>
<watzon> Paused for now. My brain needed a break haha
<FromGitter>
<Blacksmoke16> xD
<FromGitter>
<watzon> It's more of an experiment than anything, but I'd love to get it working
<hightower2>
aha supposedly after I do changeset = Repo.insert(obj), then the object is in changeset.instance
lanodan has joined #crystal-lang
<hightower2>
In Kemal, is it easy to re-reoute one route to another? Like, I have a route for /xyz, but would like / to do the same (i.e. execute the /xyz route)
<FromGitter>
<Blacksmoke16> put logic in a method
<FromGitter>
<Blacksmoke16> then could prob do like
<FromGitter>
<Blacksmoke16> `get "/xys", ->method` and `get "/", ->method`
<FromGitter>
<Blacksmoke16> something along those lines
<hightower2>
mm, yes, yes, did so but still kept 2 or 3 lines within the route itself. I guess I could put everything in the method, yes. thanks
<FromGitter>
<Blacksmoke16> 👍
livcd has quit [Remote host closed the connection]
<raz>
hightower2: re ORM, jennifer seems the most mature atm
<raz>
(i was in that spot a few weeks ago). crecto feels solid but painfully incomplete. granite sadly feels like a hack, even more incomplete.
<raz>
clear looks promising (i'm hopeful) but seems to have some severe bugs (see issue tracker) and is a huge undertaking by apparently a single guy :(
<FromGitter>
<watzon> Unfortunately clear also only supports Postgres iirc
<hightower2>
yeah clear lacks some things
<raz>
jennifer was the only one where i didn't bump into missing functionality or severe bugs so far. also a single-hero project (at first i thought it's even the same one who does clear, cause their english is very similar)
<FromGitter>
<watzon> Avram is nice, but it's pretty closely tied to Lucky
<FromGitter>
<Blacksmoke16> whats hacky about Granite?
<hightower2>
we need a de-facto standard ORM
<raz>
watzon: jennifer does postgres. even notify/listen.
<FromGitter>
<watzon> I'm hoping they make some efforts to separate it a little more and provide documentation specific to avram
<raz>
watzon: yea i had a peek at avram too. but had zero docs iirc.
<FromGitter>
<Blacksmoke16> Granite could deff be improved by removing some kinda meh stuff and starting essentially from a simpler base
<FromGitter>
<Blacksmoke16> i also like the concept of separating the querying/inserting logic from the actual model
<raz>
Blacksmoke16: well, first of all nearly no docs. it also lacked a bunch of super basic functionality (can't remember what it was right now, iirc sth related to creating objects in memory)
<FromGitter>
<Blacksmoke16> but some of that is tricky w/o reflection, i.e. how to set id
<raz>
granite has the best migrator tho (micrate). so for me, micrate + jennifer it is at the moment.
<raz>
Blacksmoke16: welp, to me it was the sum of all things (i bumped into 2 or 3 before giving up). it may be fine for others who don't need these. jennifer just was the only one that gave me a close to AR experience without weird bugs or missing stuff.
<raz>
not a fan of a bunch of jennifer things either. but the ORM-ecosystem in crystal doesn't give much choice yet, so i'm glad i found one that works at all :)
<raz>
(i'd have much preferred crecto or clear, design-wise, but they were not in a usable state for me)
<straight-shoota>
would be great to have an extensive comparison of available ORM shards which looks at the general design, but also goes into detail highlighting problems and innovative solutions
<raz>
indeed. ideally something like a side-by-side comparison "how to do X in $orm".
<straight-shoota>
And the same goes for other flooded markets like HTTP frameworks or CLI builders :D
<raz>
http frameworks are easy. use kemal or build your own :P (until that new non-singleton kemal is ready or you're willing & able to drink the constraints of amber/lucky)
<straight-shoota>
hehe
<straight-shoota>
eventually the ecosystem will consolidate. There are simply not enough niches that there was a real necessity for having 5 major implementations competing for the same use cases
<straight-shoota>
s/was/is/
<raz>
oh i love the choices. none of them are mature enough for me personally yet, but they will get there
<raz>
it's a great indicator for the splash that crystal is making. people want and do build in crystal!
<raz>
basics just still need to shake down. e.g. basics like the pg-shard itself are buggy still. the only smtp shard would exit(0) the app on a network error until a few days ago, etc. ;)
<raz>
and the ORMs are still understaffed
<straight-shoota>
yes, it's great to see many people building their ideas into shards
<raz>
crystal-core should funnel some of their donation millions into hiring an ORM team. but i understand those ferraris don't pay for themselves either :p
<straight-shoota>
no, even the gas money adds up
<raz>
yeh, i wasn't entirely serious about that one ;)
<FromGitter>
<Blacksmoke16> gotta use that athena raz 😉
<FromGitter>
<Blacksmoke16> i like to think its between kemal and amber/lucky. doesnt force anything on you, but more feature rich than kemal
<raz>
Blacksmoke16: i had a look but not my cup of tea, sorry. :) i'm sure others will love it
<FromGitter>
<Blacksmoke16> not much seems to be your cup of tea 😉
<FromGitter>
<Blacksmoke16> ORM wise only requirement I have is to support annotations on your columns
<raz>
yeh i'm very picky. in terms of web frameworks i don't want a reimpl of 10yr old patterns (sinatra / rails). i want sth that leverages the lovely crystal powers. lucky has that right but i disagreed with some choices, so ended up building basically my own lucky now
<FromGitter>
<watzon> Oh?
<straight-shoota>
which choice don't you agree with in lucky?
<raz>
Blacksmoke16: for me it's reflection (being able to discover which columns exist etc. - to generate things like validation forms), transactions, notify/listen and a few other things. i def didn't mean to diminish any of the ORMs above. use-cases differ, so i'm sure of the others will work perfectly for many
<FromGitter>
<Blacksmoke16> having columns support annotations would allow for that, as any shard could include a module and tap into ivars and such.
<FromGitter>
<Blacksmoke16> but for sure. is quite hard to balance the needs/wants of everyone. prob why there are so many ORMs?
<raz>
straight-shoota: too rigid (lucky-way or the highway), far too much boilerplate, inconsequential in some areas. (just my personal peeves). same as with ORMs, it's a great framework and surely works great for many. but after starting an app i realized i could do the same with 1/3 the LOC, so i went that route :)
<straight-shoota>
yeah, I haven't looked at lucky deeply yet
<raz>
might release mine one day, but that would be a major undertaking (writing docs etc.).
<straight-shoota>
but from what I've seen, too rigid was my impression too
renich has joined #crystal-lang
<straight-shoota>
docs will help you, too when you return to it after doing something else :D
<raz>
no, i don't need no docs. crystal is amazing at making everything click into place with compile errors. even tho the macros make some of them non-obvious ;)
<straight-shoota>
I know I often enough have to look up the documentation for things I've written at some point but can't remember
<FromGitter>
<watzon> Same
<FromGitter>
<Blacksmoke16> id be curious of hearing any specifics of what wasn't your cup of tea for Athena. not too many people using it so actual feedback isnt too common :p
<FromGitter>
<Blacksmoke16> i.e. if anything could be made more clear in the docs, or API improvements etc
yxhuvud has quit [Read error: Connection reset by peer]
yxhuvud has joined #crystal-lang
<FromGitter>
<Blacksmoke16> if its just general architecture np
<FromGitter>
<watzon> That would be my advice. Good docs increase usage.
<FromGitter>
<watzon> I highly recommend docasaurus
<straight-shoota>
I guess one thing I'm not 100% comfortable with is the heavy use of annotations and macros. Not saying it's bad, it's actually a good idea and might be a great design for this kind of thing.
<raz>
Blacksmoke16: yea, just different philosophies really. is there a good pastebin with crystal highlighting? hm
<straight-shoota>
carc.in :D
<FromGitter>
<Blacksmoke16> i like to think i document everything well. i think it could deff use some like cookbook/guide style ones. been trying to keep everything in the API docs for now just to avoid stuff getting out of date
<FromGitter>
<watzon> I don't know of one that supports Crystal specifically. I use hastebin and just set the extension to .rb
<raz>
heh, well, if it didn't chop off the code on the right... :P
<raz>
watzon: hm yea, hastebin doesn't save for me atm :(
<raz>
503, seems their webserver is taking a nap
<FromGitter>
<watzon> Hmm that's weird
<straight-shoota>
Blacksmoke16: A getting started guide would be great. IIRC you had some articles on dev.to or so?
<FromGitter>
<Blacksmoke16> yea, goes thru setting it up with granite to make a blog
<FromGitter>
<Blacksmoke16> been keeping it up to date
<raz>
ohhh it works! i was on hastebin.com
<straight-shoota>
That should be linked in the readme and API docs
<FromGitter>
<watzon> It's FOSS software, so there are quite a few sites using the same thing
<FromGitter>
<mattrberry> I'm a little confused about how macros and/or class getters/setters work. I'm trying to create something like
<FromGitter>
<Blacksmoke16> straight-shoota: to be fair the macro usage isn't as widespread as you'd think, each core shard has like one major file that uses them, but really only part of athena core that uses it is for adding stuff to the router
<straight-shoota>
Also I find it very weird that the API docs link ends up in a deep namespace
<FromGitter>
<Blacksmoke16> what about it? kinda just how the docs work since everything is under a global namespace
<FromGitter>
<Blacksmoke16> and each component has their own namespace under that
<straight-shoota>
Yeah I understand that
<FromGitter>
<mattrberry> I'm a little confused about how macros and/or class getters/setters work. I'm trying to create something like ⏎ ⏎ ```@af = 0x1234``` ⏎ ⏎ would result in @a == 0x12 and @f == 0x34. ... [https://gitter.im/crystal-lang/crystal?at=5eb48b12347bd6163060a7ba]
<raz>
blacksmoke16: in case you're curious, that's what my signup-form looks like: https://hasteb.in/nugarake.rb (threw in a snippet of the root component to show the routing etc.). that's the entirety of it (my boilerplate allergy is strong) and it generates a full form with client + server-side validation (unpoly js) etc. so conceptually it's very close to lucky, i just hadn't managed to bring lucky down to that level of verbosity.
<FromGitter>
<Blacksmoke16> @mattrberry you're trying to declare ivars in the top level namespace
<straight-shoota>
Blacksmoke16: It's just not clear how everything belongs together. athena looks like the main shard of the framework but its documentation link leeds to the routing component
<FromGitter>
<mattrberry> @Blacksmoke16 I have that macro inside of a class
<FromGitter>
<mattrberry> And the `define_register a, f` is also inside of the class
<FromGitter>
<Blacksmoke16> so whats the problem exactly?
<FromGitter>
<mattrberry> @a and @f are not being set
<FromGitter>
<Blacksmoke16> you initialize them to `0_u8` so yea
<straight-shoota>
mattrberry, the issue is `@af = 0x1234` is an assignment to an ivar
<FromGitter>
<Blacksmoke16> straight-shoota: yea i could prob document that better. the thought is that `Athena` is the framework, but the framework itself is made up of various components, one of which is `Routing`.
<straight-shoota>
it doesn't call the setter method you define in the macro
<FromGitter>
<watzon> `{{upper.id}}{{lower.id}}` is smashing `a` and `f` together
<FromGitter>
<watzon> So you're going to get `@af` not `@a` and `@f`
<FromGitter>
<mattrberry> @straight-shoota How would I go about making those setters work?
<straight-shoota>
`af = 0x1234`
<straight-shoota>
or rather `self.af = 0x1234`
<FromGitter>
<mattrberry> Ahh, so `self.af = ...` rather than `@af = ...` ?
<straight-shoota>
exactly
<straight-shoota>
the latter is a direct assignment to an ivar
<straight-shoota>
you can't override that with a method
<straight-shoota>
same with getters: `@a` directly accesses the ivar, `a` calls the getter (which typically returns `@a`)
<straight-shoota>
watzon, how does your `html_for` helper work? Is it just DSL for the form block?
<FromGitter>
<mattrberry> Awesome, thank you @straight-shoota and everyone for the help!
<straight-shoota>
you're welcome
<FromGitter>
<watzon> @straight-shoota where? Sorry I write a lot of code haha, I don't remember where `html_for` is.
<FromGitter>
<Blacksmoke16> raz: yea it also helps i kinda been focusing on API side of things
<straight-shoota>
ah, sry. I meant raz :D
<FromGitter>
<watzon> Ahh ok lol
<straight-shoota>
I had the hastebin open for a while
<straight-shoota>
Regarding ORMs: I really don't like when query DSLs have pseudo SQL fragments expressed as literal Crystal code. Clear calls this expression engine.
<raz>
straight-shoota: well, it's a component (everything is). yes, DSL by nature, but it's not static. it takes the a jennifer model as input and translates the fields to html form elements (or anything really, it uses type-based renderer classes). i.e. in that example it creates email-input or the email attr, passwords for the password, and takes care of all the validation, populating values after POST, adding the html attrs for client-side validation etc.
<raz>
it even does the "passwords must match" thing etc. :)
<straight-shoota>
raz: okay, so it's specific to the form builder. I was just wondering if it was a general helper which the name suggests. And for that it seems weird that it receives an object and property names
<FromGitter>
<Uzay-G> What would be the best way to generate a secret token, like an api token, in crystal?
<straight-shoota>
@Uzay-G you could use Random#base64 or Random#hex
<raz>
straight-shoota: well it is general. html_for(u, "email", :input, ..) takes the User object (jennifer) and translates the "email" attr using the :input renderer. it can and does also take other things. (html_for is a bit of a misnomer, it's the renderer called 'input' that decides what actually comes out)
<straight-shoota>
I guess then I would have expected :input to be the first argument :D
<straight-shoota>
Thanks for clarifying
<raz>
yea, well, all still wip. ;) if i ever release it will need docs and cleanups. it's just how i want to write web stuff. abstract all those nasty details away so i can focus on what matters, not re-write the same validation code a hundred times (and then re-write it again after adding another field :p)
<FromGitter>
<Blacksmoke16> then you use serialize/validate your models directly, versus having separate things that are essentially just boilerplate
<raz>
yap, can very much agree with that
<raz>
except for one thing
<FromGitter>
<Blacksmoke16> and since it uses annotations, its agnostic of what actual thing you use, versus tied to each specific orm or whatever
<raz>
if i understand it right, you have to duplicate the model validations there?
<raz>
(e.g. min-len on model *and* in annotation for form-generation)
<FromGitter>
<Blacksmoke16> hm?
<FromGitter>
<Blacksmoke16> ah you mean for validation and column creation?
<raz>
yea, does @[Assert::NotBlank] only apply to the generated form
<raz>
or also add the not-blank condition to when you try to validate/save the model instanec
<FromGitter>
<Blacksmoke16> the validations are not really tied to the ORM, they're totally generic
<FromGitter>
<Blacksmoke16> but they *could* be used in both
<raz>
ok yea. it's not a big deal i think. but ideally validations should be declared only once
<raz>
cause otherwise they can disagree, and we all know what then happens :p
<FromGitter>
<Blacksmoke16> yea, also granted i havent done anything with forms yet
<FromGitter>
<Blacksmoke16> so dont have any specific answers on that
<raz>
ah gotcha. yap, my focus has been on this forms + validation thing from the start. cause over the past 10yrs i realized that's what i spend 95% of my webdev time in. basic CRUD nonsense that i just don't want to think about.
<FromGitter>
<Blacksmoke16> kinda been basing my stuff on symfony, so like their example is
<FromGitter>
<Blacksmoke16> so i guess the form just knows about the validations on the ivars that map to fields
<FromGitter>
<Blacksmoke16> ah, the submitted for exposes a `isValid()` method that runs the validations
<raz>
yup, that looks about right. the one thing that most form builders don't do is to automatically add the right validations, field-len etc.
<raz>
they want you to specify things like "min-len" on each form instance, which makes no sense to me. the model has a min-len, you never want to have a form with a different one.
<raz>
(and i don't want to remember what the required constraints etc. are every time i write a form involving a user)
<FromGitter>
<Blacksmoke16> mhm
<FromGitter>
<Blacksmoke16> is what i like about the annotation approach, it provides an agnostic set of validations not tied to a particular part of your app
<FromGitter>
<Blacksmoke16> instead of your form having its set, ORM having its set, etc
<raz>
yea the important bits is that the constraints can be defined *once* and are not repeated anywhere.
<FromGitter>
<Blacksmoke16> exactly
<raz>
i'm not particularly married to where/how that definition happens, but model seems the natural place
<FromGitter>
<Blacksmoke16> we been slowing moving our models to this type of approach, i.e. serializing/validating the models directly versus relying on other types for crud
<FromGitter>
<Blacksmoke16> much more efficient
<raz>
yep. i'm working on nested/incremental forms now (e.g. plus-button to add more instances of $item).
<FromGitter>
<Blacksmoke16> also helps being able to use common interfaces for validating different things. I.e. the annotations you apply to your model could also be newed up directly and used in a form if its not worth having a model for
<FromGitter>
<Blacksmoke16> or same validators for query params etc
<raz>
that's where this approach saves hours and days of headaches
* raz
nods
<raz>
sounds like we're on the same html page :D
<raz>
the next gen of crystal webframeworks is gonna be awesome. (even awesomer than the current batch)
<FromGitter>
<Blacksmoke16> heh, im working on it 😉
<FromGitter>
<Blacksmoke16> lol
<FromGitter>
<Blacksmoke16> now just need to get you on board with the event approach hehe
<raz>
yeh, you put all the work in with docs, actually releasing it etc. kudos to that!
<raz>
oh, i'm using events. :p
<raz>
(not for forms, but for everything else)
<FromGitter>
<Blacksmoke16> now im even more curious what you meant by different philosophies
<raz>
interesting you mention that, cause i haven't managed my head around how to use them for forms/model persistence.
<raz>
that looks like a callback to me. with event i was thinking operation/kafka (operation in the lucky sense)
<FromGitter>
<Blacksmoke16> prob for like altering form data/validating input etc
<FromGitter>
<Blacksmoke16> ah gotcha
<raz>
yea, i think that kind of event is nice, too. (for me it registers more as a "callback", terminology-wise :D)
<FromGitter>
<Blacksmoke16> it gets the event name because the library that emits them calls them events
<FromGitter>
<Blacksmoke16> i.e. it "emits" some event that other listeners can act upon (or not)
<raz>
but i found it also gets in the way sometimes. e.g. sometimes i want to do extra stuff at POST-time, and events get in the way (wrong execution order, loss of variable scope)
<raz>
but yes, having them is def a good idea
<FromGitter>
<Blacksmoke16> depends on how you architect things, gets messy when they start to depend on eachother etc
<FromGitter>
<Blacksmoke16> as you mention, specific orders and stuff
<raz>
(my current take is that i want both. event-handler but also meaningful execution flow / return values so things can be wired up as needed)
<raz>
yep, event-chaining is a slippery slope (cf. javascript)
<FromGitter>
<Blacksmoke16> athena uses my event lib internally which allows for some of that, at least defining events/listeners, determining order they get executed in
<raz>
onValidate, onSave are very nice in 99% of cases. just don't leave your users out in the cold in the 1% case where they really need basically only 1 line right in between the two ;)
<raz>
(can't think of a good concrete example right now, but definitely been there :D)
<FromGitter>
<Blacksmoke16> their event system works by you emit the event, and the listeners mutate it, then you get the event back in your code
<FromGitter>
<Blacksmoke16> er the code that emitted the event
<raz>
yup yup, when done right then at least in form-handling they can do everything that's needed i think. and it's a great pattern in general
<FromGitter>
<Blacksmoke16> mhm, works well in framework land too, listeners can add/remove/alter response headers/cookies
<FromGitter>
<Blacksmoke16> agnostic of eachother
<raz>
well, that's where the lie starts :P
<raz>
those terrible set-cookie headers...
<FromGitter>
<Blacksmoke16> 🍪
<raz>
(have to store the ones to be set in one place, but only later actually write them out)
<FromGitter>
<Blacksmoke16> hm?
<raz>
but yea, i see what you mean and agree with it :)
<raz>
well, strictly speaking you can't "alter" a set-cookie in an event that may fire multiple times from anywhere
<raz>
if it fires twice to set "foobar"-cookie twice, you have two headers
<FromGitter>
<Blacksmoke16> sorry, to be clear i mean something like one listeners could override headers by other listeners
<FromGitter>
<Blacksmoke16> like imagine some shard has a default thing, but you could define your own listener that runs after the default to change some values
<raz>
yep, also sorry, that was too specific (can of course be solved). CookieJar just been sth i've been annoyed with recently
<FromGitter>
<Blacksmoke16> (ofc would be better ways to handle that but you get the idea)
<raz>
yup yup
<FromGitter>
<Blacksmoke16> was one thing i noticed, headers get sent when you write to the response IO
<FromGitter>
<Blacksmoke16> which can be quite hard to debug
Sharcho has quit [Quit: Leaving]
<raz>
yea, i was getting too specific there. response IO can be tricky (with headers at all) when you want to write as you render to make it fast.
<raz>
but that's kinda specific to the lucky-style render-method (html as code)
<raz>
e.g. you've written a <title> a while ago. but now you want to change it (route went elsewhere).
<FromGitter>
<Blacksmoke16> gl
<raz>
yeh, that one ended up easy actually. fixed maxlen for title, remember offset, seek and overwrite :p
<raz>
anyweh, pizza time. lookin forward to more athena in the future :)
<FromGitter>
<Blacksmoke16> I'd think it would be right up your alley based on all this ha
<FromGitter>
<Blacksmoke16> But I'll keep you posted, waiting on next crystal version ATM, till I can release some cool di stuff
<raz>
maybe. prob not this version yet, but perhaps a future one. we just gotta keep writing these web frameworks till one of them is good enough so nobody bothers anymore :)
<FromGitter>
<Blacksmoke16> Hehe
<straight-shoota>
Maybe humankind will have advanced by that time so we don't use websites anymore
<straight-shoota>
don't know what would be the successor, but might be some AI driven blockchain-to-brain interface