dry-auto_inject icon indicating copy to clipboard operation
dry-auto_inject copied to clipboard

Strategy to inject dependencies via class- and instance-methods

Open maxhollmann opened this issue 4 years ago • 15 comments

Injects dependencies using methods on the class and instance:

module Test
  AutoInject = Dry::AutoInject(some_dep: 'The dependency').methods
end

class SomeClass
  include Test::AutoInject[:some_dep]
end

SomeClass.some_dep
# => "The dependency"

SomeClass.new.some_dep
# => "The dependency"

with_other_dep = SomeClass.with_deps(some_dep: 'Other')
with_other_dep.some_dep
# => "Other"

with_other_dep.new.some_dep
# => "Other"

This leaves the constructor free to receive other arguments, which makes integrating this library into existing projects much easier.

maxhollmann avatar Nov 20 '20 12:11 maxhollmann

Not sure why that kwargs spec fails, it passes locally...

maxhollmann avatar Nov 20 '20 13:11 maxhollmann

Hey, thanks for the PR. In the future, it's better to first propose a new feature on our discussion forum. I'm not sure if this can be accepted so first I'd appreciate if you could expand on the idea that this would help integrating auto_inject with existing projects. I just need to be sure that in some cases this would indeed be helpful and using existing strategies wouldn't be an option.

solnic avatar Nov 23 '20 20:11 solnic

Found this while trying to use dry-rails with ActiveJob. Using this strategy would allow injection for jobs. I'm using the Container directly for now. ActiveJob tries to serialize all constructor args, which most dependencies won't serialize and would probably not be good even if they did.

+1 for this strategy

candland avatar Nov 24 '20 19:11 candland

@candland that's a really good use case. Thanks. I think we could include it then. WDYT @timriley ?

solnic avatar Dec 08 '20 07:12 solnic

you should all just use effects and call it a day 😆

flash-gordon avatar Dec 08 '20 11:12 flash-gordon

@flash-gordon oh right, I'm much more inclined to switch to effects altogether at some point (sooner than later for sure), but for now, this sounds reasonable, no?

solnic avatar Dec 08 '20 11:12 solnic

@solnic I don't have preferences over injection strategies. In this case, it looks strange that in order to inject a dep you'll get an anonymous copy of a class. I might have unwanted side effects but I guess it's up to the user to deal with it.

flash-gordon avatar Dec 08 '20 12:12 flash-gordon

@flash-gordon what are effects? Where I can read more about them?

candland avatar Dec 08 '20 13:12 candland

@candland https://dry-rb.org/gems/dry-effects/0.1/effects/resolve/ I also have a sample project with dry-everything https://github.com/flash-gordon/rt-tracker And there's an example of using effects in an existing rails project https://github.com/flash-gordon/forem

flash-gordon avatar Dec 08 '20 14:12 flash-gordon

@maxhollmann woud it be possible for you to solve your problem using an effect-based injector like @flash-gordon suggests?

solnic avatar Dec 09 '20 07:12 solnic

That might work, I'll check in the coming days. I share flash-gordon's concern with the anonymous subclass, so I'd be happy if I can get around it using the effects injector.

maxhollmann avatar Dec 09 '20 15:12 maxhollmann

@maxhollmann cool! I think it's worth mentioning that we'll probably switch to an effect-based injector as the default way (maybe even the only officially supported way) at some point in the future, so testing this out would be very helpful 🙂

solnic avatar Dec 09 '20 15:12 solnic

Okay, I finally got around to looking at the effects provider. It would indeed be much cleaner than this solution, but I haven't found a good way to provide the default dependencies everywhere in a Rails app (server, tests, console, rake/thor tasks). Does anyone know of a clean way to do this?

maxhollmann avatar Jan 11 '21 12:01 maxhollmann

@maxhollmann there's no out-of-the-box solution I would say, I'm still gathering use cases to wrap them with a nice API. Normally, I create a single effect stack and re-use it in places like CLI or background tasks. This is how it's typically done: https://github.com/flash-gordon/rt-tracker/blob/main/lib/rt_tracker/handlers_stack.rb This is how it's used: https://github.com/flash-gordon/rt-tracker/blob/825855e07d135ed73547a541e2dbd73c6408956c/Rakefile#L13-L23 Really, nothing fancy.

flash-gordon avatar Jan 11 '21 16:01 flash-gordon

Really, nothing fancy.

EXACTLY, this is what makes this so freaking awesome 🙂

solnic avatar Jan 13 '21 04:01 solnic