Same as Dry::AutoInject
but uses keyword arguments. This allows you to replace just one dependency at a time and rest will use the defaults provided by the container.
require 'dry-container'
MEMORY_DB = Hash[messages:[]]
module MyApp
container = Dry::Container.new
container.register('message.store', -> { MEMORY_DB[:messages] })
container.register(:messenger, -> (msg) { puts msg })
AutoInject = Dry::KeyInject(container)
def self.Inject(*keys)
AutoInject[*keys]
end
class Service
include MyApp::Inject('message.store', :messenger)
def call(params)
store << params[:msg]
messenger.(params[:msg])
end
end
end
svc = MyApp::Service.new
svc.(msg: "Hello")
# => Hello
puts MEMORY_DB[:messages]
# => Hello
puts [svc.public_methods - Object.new.public_methods].join(', ')
# => call, store, messenger
puts MyApp::Service.container.inspect
# => #<Dry::Container:0x007fc3a3b39c28>
svc = MyApp::Service.new(messenger: -> (msg) { puts "#{msg.to_s.upcase}!" })
svc.(msg: "Hello")
# => HELLO!
This one is ideal when you have no control over initialization (e.g. Rails controllers). Getter injection simply creates reader accessors with chosen visibility (private/protected/public). Default is public visibility as in original AutoInject strategy. Only way how you can change those dependcies is via the container, which is assigned to the class object or via stubbing in the tests.
require 'dry-container'
MEMORY_DB = Hash[messages:[]]
module MyApp
container = Dry::Container.new
container.register('message.store', -> { MEMORY_DB[:messages] })
container.register(:messenger, -> (msg) { puts msg })
AutoInject = Dry::GetterInject(container, :private)
def self.Inject(*keys)
AutoInject[*keys]
end
class Controller
include MyApp::Inject('message.store', :messenger)
def initialize(params)
@params = params
end
def show
store << params[:msg]
messenger.(params[:msg])
end
protected
attr_reader :params
end
end
ctrl = MyApp::Controller.new(msg: "Hello")
ctrl.show
# => Hello
puts MEMORY_DB[:messages]
# => Hello
puts ctrl.public_methods - Object.new.public_methods
# => show
puts MyApp::Controller.container.inspect
# => #<Dry::Container:0x007fc3a3b39c28>
This one is extension of the Dry::GetterInject
and it creates both readers (with given visibility) and (always public) writers which allows you to do setter DI. This allows you plugin replacement of any dependency during runtime, which gives you more control and make the given class more reusable. However every post-initialize mutation makes the class less stable so it should be used with care. You should always prefer constructor DI as is implemented in Dry::AutoInject
or Dry::KeyInject
.
require 'dry-container'
MEMORY_DB = Hash[messages:[]]
module MyApp
container = Dry::Container.new
container.register('message.store', -> { MEMORY_DB[:messages] })
container.register(:messenger, -> (msg) { puts msg })
AutoInject = Dry::SetterInject(container, :private)
def self.Inject(*keys)
AutoInject[*keys]
end
class Controller
include MyApp::Inject('message.store', :messenger)
def initialize(params)
@params = params
end
def show
store << params[:msg]
messenger.(params[:msg])
end
protected
attr_reader :params
end
end
ctrl = MyApp::Controller.new(msg: "Hello")
ctrl.show
# => Hello
puts MEMORY_DB[:messages]
# => Hello
puts [ctrl.public_methods - Object.new.public_methods].join(', ')
# => show
puts MyApp::Controller.container.inspect
# => #<Dry::Container:0x007fc3a3b39c28>
ctrl.messenger = -> (msg) { puts "#{msg.to_s.upcase}!" }
ctrl.show
# => HELLO!