This was a good read! I know there aren’t many DI implementations in Crystal, so was interesting to see how someone else went about implementing it. I have a few thoughts/questions:
The next trick is to use the unsafe
.allocatemethod to grab some uninitialised memory where we can put our object. We then just call the rightinitializemethod (as defined bymethod) which will set the instance variables. That’s just a matter of generating a method call from the information inmethod:
Is there a reason you have to use .allocate? If the Inject annotation is always applied to the initialize method, it should be safe to just do {{ @type }}.new(...) and let Crystal itself find that overload?
Since Crystal macros don’t have methods, every time we want to access the specially-named getter, we have to duplicate that snippet.
I feel you
, would love to get more feedback on/move forward with RFC 0018: Macro Methods by Blacksmoke16 · Pull Request #18 · crystal-lang/rfcs · GitHub as a way to DRY things up a bit. I found /[^\w]/ to be a bit more robust as well.
For subscopes that correspond to a particular action (like an HTTP request) you need to be able to put values into the dependency graph.
This feels odd to me (assuming it’s not just for example purposes). Like would it not be better to not have the server context be in the DI container, but passed to a related service as an argument? E.g. def process(context : HTTP::Server::Context)? The scoping concept is neat but I think I’d have to see some more real-world use cases to fully understand its benefit.