Skip to content

low-rb/low_dependency

Repository files navigation

Gem version GitHub repo Codeberg repo

LowDependency

Automatic Dependency Injection where you get to see and keep control of the constructor.

Injection

Inject a dependency:

class MyClass
  include LowType

  def initialize(my_dependency: Dependency)
    @my_dependency = my_dependency # => The 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 # => The dependency is injected.
  end
end

This method hides and creates the constructor on your behalf.

Providers

Provide the dependency with:

LowDependency.provide(:my_dependency) do
  MyDependency.new
end

Namespaced string keys are fine too:

LowDependency.provide('billing.payment_provider') do
  PaymentProvider.new
end

Mixing dependency types

LowDependency lets you do something special; mix "classical" dependency injection (passing an arg to new) with "automatic" style dependency injection (populating an arg via a provider):

# Define both an "automatic" and a "classical" dependency:
class MyClass
  include LowType

  def initialize(automatic_dependency: Dependency, classical_dependency:)
    @automatic_dependency = automatic_dependency
    @classical_dependency = classical_dependency
  end
end

# Now bring it all together by calling:
MyClass.new(classical_dependency: ClassicalDependency.new)

The automatic_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 🥣

API

Dependency Expression

The def(dependency: Dependency) syntax is an Expression; an object composed via a query builder like interface. A Dependency Expression defines the name of the local variable, as well as the name of the provider that will inject the dependency into your code.

To define a provider with a different name to that of the local variable do:

def initialize(dependency_one: Dependency | :provider_one, dependency_two: Dependency | 'billing.provider_two')
  dependency_one # => Dependency injected from :provider_one.
  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.

Traditional Dependency

The include style syntax supports the same functionallity as the dependency expression syntax.

Multiple dependencies:

class MyClass
  include LowDependency[:dependency_one, :dependency_two]
end

Dependencies 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

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,
  ]
end

Installation

Add gem 'low_dependency' to your Gemfile then:

bundle install

About

Dependency Injection in crisp and clear syntax

Resources

License

Stars

Watchers

Forks

Packages

No packages published