-
-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for singletons with auto-register and auto-inject #21
Conversation
You can already do this with a custom loader, the idea being that the simple default covers the 95% and the other cases can configure it. See https://github.com/dry-rb/dry-component/blob/39f39f8e76eefff860d7959c385886e059421e5a/spec/unit/container/auto_register_spec.rb#L40-L64 |
So I guess the question here is whether this makes sense to go in our default loader. Is it something we want to offer out of the box? I also saw @solnic in gitter mentioning that quite a many objects could be registered as singletons with the container, even if they're not Singletons in the strict sense (i.e. not responding to |
I was against adding support for handling singleton instantiation, but being singleton-aware is OK and we should probably support this as a built-in, optional feature. |
This is dry-auto_inject’s minimum now
…en-resolving-individual-components Support default namespace when loading files using shorthand identifiers
@AMHOL Yes, I started with a custom loader. The second half of this is is to change auto-inject to use the loader:
The above change is enough to support singletons with custom loaders. @solnic When you say build-in, optional feature do you mean it should be configurable? @timriley before using dry-component I was using a custom container registry and resolver to get singleton behavior. I believe this is a common use case. |
subject(:component) { Dry::Component::Loader.new('test/bar') } | ||
|
||
it_behaves_like 'a valid component' | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something's wrong with indentation here
I just realized that having it configurable would be difficult to use, since loaders are per-component IIRC, so I think it's OK to make default loader singleton-aware. FWIW we want to use singletons in most of the cases anyway :) @timriley you ok with merging this in? |
@solnic Yep, I'm good with merging this. (I can take care of this on Monday if you'd like!) In general, I think it'd be good to make it easier for more objects to be handled as singletons, so this is a good first step :) |
@rx You happy take a final pass at this and get those merge conflicts sorted out? Thanks! |
…existing-keys Return immediately from load_component if the key already exists
Yes, I'm happy to get the merge conflicts sorted out. @solnic https://github.com/solnic There is another location that probably should be changed in the I didn't commit this change because it changes the default behavior and I I believe it should be changed, but it changes what is passed to the block, Here is the additional proposed change: diff --git a/lib/dry/component/container.rb b/lib/dry/component/container.rb
On Sun, Jul 31, 2016 at 1:41 AM, Tim Riley notifications@github.com wrote:
|
Which "block auto_registration!"? |
When I was spelunking the code to put in support for singletons. I tried using auto_registration! and passing a block. The current implementation optionally takes a block and yields to that block in the container registration call. At the time I thought I might be able to control the lifecycle of a singleton by providing code that is put in the container registry. Passing a block to the method would have been useful, except the parameter that is passed to that block is a call to loader.constant. That, in essence, loads every class at the time of registration. (The default behavior lazy loads classes.) I had some files in my loaded tree that did not strictly follow the module=directory and class=filename naming convention and the container failed to 'boot'. As a result, I was unable to pass a block and get the same lazy loading behavior. I'm recommending that a single line of code be changed that registers the object to pass the loader instead. If anyone is even using that construct, it is a more useful implementation. It really is no big deal, but since I had noticed the difference in behavior from the default behavior, I thought I'd make the recommendation. You could equally argue that the loader provides the necessary flexibility and the code that calls the block is unnecessary. Here is the full implementation of the code I'm referring to:
And here is the single line change I'm proposing:
|
This sounds reasonable! @timriley would that work for you? It shouldn't On 1 August 2016 at 22:05:11, Russell Edens (notifications@github.com)
|
This change sounds smart indeed! @rx, would love for you to put it forward, either in this PR or another, I don't mind :) |
… the loader instead of the loader.constant.
@timriley I made a pass at pulling this forward. I'm not sure I did it correctly. I merged upstream/master into my forked master. Then I merged those changes to this branch (singleton_fix) and fixed conflicts. The commit list of this pull request now shows those items merged from origin/mainline. I haven't done this enough to know if this is expected or not. Let me know if I need to open a new PR or not. Thanks. |
@rx this doesn't look right, we shouldn't have commits from master in this branch. The simplest way is to do |
@solnic Roger that. Didn't seem right. I should have a cleaned up PR On Tue, Aug 2, 2016 at 1:29 PM, Piotr Solnica notifications@github.com
|
Closed in favor of #25 |
Hey Guys,
I have a 'repository' that is is a singleton and I ran into an issue trying to use a singleton using auto_registration and auto-inject.
This change allows a class like the following you to be used with the dry-component auto-register and auto-inject:
The change does not change the behavior for any other classes besides singleton's. (At least that was my intention.)
There are two changes - one is to the default loader to see if the object responds to :instance and not :new. This means it quacks like a singleton and we call .instance(_args) instead of .new(_args).
The other change is to the load_component method, where it was calling .new directly instead of using the loader instance method.
There is another location that probably should be changed in the auto_registration! method where a block is passed. It loads the class before calling the block. This means that if you pass a block in you can't lazy load your components. I didn't commit this change because it changes the default behavior and I didn't need it to get singleton behavior working, but I think it should be passing the loader to the block and letting the block decide how to load/register.
Like so:
I added specs for the changes.
I also added RubyMine .idea to the .gitignore.
The changes are based off the v0.3.0 release, but should merge into mainline with little trouble. (I ran into an Inject issue when I pulled from mainline.)
Thanks for considering this change. I'm really enjoying creating clean architecture/code using the dry ecosystem, thanks for all your hard work.