Automatic Dependency Injection where you get to see and keep control of the constructor.
Inject a dependency:
class MyClass
include LowType
def initialize(my_dependency: Dependency)
@my_dependency = my_dependency # => "my_dependency" is injected.
end
endℹ️ The above example requires LowType in order to use the def(dependency: Dependency) syntax.
Or you may like to use the more traditional include syntax:
class MyClass
include LowDependency[:my_dependency]
def my_method
@my_dependency # => "@my_dependency" is injected.
end
endThis method hides and creates the constructor on your behalf.
Provide the dependency with:
LowDependency.provide(:my_dependency) do
MyDependency.new
endNamespaced string keys are fine too:
LowDependency.provide('billing.payment_provider') do
PaymentProvider.new
endLowDependency lets you do something special; mix "classical" dependency injection (passing an arg to new) with "provider" style dependency injection (populating an arg via a framework):
LowDependency.provide(:provider_dependency) do
ProviderDependency.new
end
# Define both a "provider" and a "classical" dependency:
class MyClass
include LowType
def initialize(provider_dependency: Dependency, classical_dependency:)
@provider_dependency = provider_dependency
@classical_dependency = classical_dependency
end
end
# Now bring it all together by calling:
MyClass.new(classical_dependency: ClassicalDependency.new)The provider_dependency argument will automatically be injected by LowDependency!
Now you get to have your classical dependency cake 🍰 and eat it too with an automatically injected dependency spoon 🥣
A Dependency Expression defines the dependency to be injected, the provider that will inject it and the name of the local variable that it will be made available as.
The def(dependency: Dependency) syntax is an Expression; an object composed via a query builder like interface. It follows the same logically consistent rules as other expressions in the Expressions API.
To define a provider with a different name to that of the local variable do:
def initialize(dependency_one: Dependency | :provider_one)
dependency_one # => Dependency injected from :provider_one.
endFor providers with string keys do:
def initialize(dependency_two: Dependency | 'billing.provider_two')
dependency_two # => Dependency injected from 'billing.provider_two'.
endℹ️ The value after the pipe | becomes the provider key. When the provider key is omitted then the name of the positional/keyword argument is substituted as the provider key instead.
The include style syntax supports the same functionallity as the dependency expression syntax.
Multiple dependencies:
class MyClass
include LowDependency[:dependency_one, :dependency_two]
endDependencies with differing local variable/provider keys:
class MyClass
include LowDependency[dependency_one: :provider_one, dependency_two: 'billing.provider_two']
# Instance variables @dependency_one and @dependency_two are now available.
endℹ️ Provider keys with a namespace such as 'billing.provider_two' will have their dependency injected without the namespace; the variable will just be @provider_two.
Separating many dependencies on multiple lines:
class MyClass
include LowDependency[
dependency_one: :provider_one,
dependency_two: 'billing.provider_two',
:dependency_three,
:four_dependencies_is_still_quite_reasonable_yeah,
]
endAdd gem 'low_dependency' to your Gemfile then:
bundle install