Module: Flows::Plugin::DependencyInjector

Includes:
InheritanceCallback, Util::InheritableSingletonVars::DupStrategy.make_module( '@dependencies' => {} ), Util::PrependToClass.make_module do def initialize(*args, **kwargs, &block) # rubocop:disable Metrics/MethodLength if @__dependencies_injected__ if kwargs.empty? # https://bugs.ruby-lang.org/issues/14415 super(*args, &block) else super(*args, **kwargs, &block) end return end @__dependencies_injected__ = true klass = self.class DependencyList.new( klass: klass, definitions: klass.dependencies, provided_values: kwargs[:dependencies].dup || {} ).inject_to(self) filtered_kwargs = kwargs.reject { |key, _| key == :dependencies } if filtered_kwargs.empty? # https://bugs.ruby-lang.org/issues/14415 super(*args, &block) else super(*args, **filtered_kwargs, &block) end end end
Defined in:
lib/flows/plugin/dependency_injector.rb,
lib/flows/plugin/dependency_injector/errors.rb,
lib/flows/plugin/dependency_injector/dependency.rb,
lib/flows/plugin/dependency_injector/dependency_list.rb,
lib/flows/plugin/dependency_injector/dependency_definition.rb

Overview

Allows to inject dependencies on the initialization step.

After including this module you inject dependencies by providing :dependencies key to your initializer:

x = MyClass.new(dependencies: { my_dep: -> { 'Hi' } })
x.my_dep
# => 'Hi'

Keys are dependency names. Dependency will be injected as a public method with dependency name. Values are dependencies itself.

You can also require some dependencies to be present. If required dependency is missed - MissingDependencyError will be raised.

If an optional dependency has no default - MissingDependencyDefaultError will be raised.

For an optional dependency default value must be provided.

You can provide a type for the dependency. Type check uses case equality (===). So, it works like Ruby's case. In case of type mismatch UnexpectedDependencyTypeError will be raised.

dependency :name, type: String # name should be a string

# by the way, you can use lambdas like in Ruby's `case`
dependency :age, type: ->(x) { x.is_a?(Number) && x > 0 && x < 100 }

If you're trying to inject undeclared dependency - UnexpectedDependencyError will be raised.

Inheritance is supported and dependency definitions will be inherited into child classes.

Examples:


class MyClass
  include Flows::Plugin::DependencyInjector

  dependency :logger, required: true
  dependency :name, default: 'Boris', type: String # by default dependency is optional.

  attr_reader :data

  def initializer(data)
    @data = data
  end

  def log_the_name
    logger.call(name)
  end
end

class Logger
  def self.call(msg)
    puts msg
  end
end

x = MyClass.new('DATA', dependencies: {
  logger: Logger
})

x.data
# => 'DATA'

x.name
# => 'Boris'

x.logger.call('Hello')
# prints 'Hello'

x.log_the_name
# prints 'Boris'

Since:

  • 0.4.0

Defined Under Namespace

Modules: DSL, InheritanceCallback Classes: Dependency, DependencyDefinition, DependencyList, Error, MissingDependencyDefaultError, MissingDependencyError, UnexpectedDependencyError, UnexpectedDependencyTypeError

Constant Summary collapse

NO_TYPE =

Placeholder for empty type. We cannot use nil because value can be nil.

Since:

  • 0.4.0

:__no_type__
NO_DEFAULT =

Placeholder for empty default. We cannot use nil because value can be nil.

Since:

  • 0.4.0

:__no_default__
NO_VALUE =

Placeholder for empty value. We cannot use nil because value can be nil.

Since:

  • 0.4.0

:__no_value__
SingletonVarsSetup =

Since:

  • 0.4.0

Flows::Util::InheritableSingletonVars::DupStrategy.make_module(
  '@dependencies' => {}
)
InitializerWrapper =

Since:

  • 0.4.0

Util::PrependToClass.make_module do
  def initialize(*args, **kwargs, &block) # rubocop:disable Metrics/MethodLength
    if @__dependencies_injected__
      if kwargs.empty? # https://bugs.ruby-lang.org/issues/14415
        super(*args, &block)
      else
        super(*args, **kwargs, &block)
      end

      return
    end
    @__dependencies_injected__ = true

    klass = self.class
    DependencyList.new(
      klass: klass,
      definitions: klass.dependencies,
      provided_values: kwargs[:dependencies].dup || {}
    ).inject_to(self)

    filtered_kwargs = kwargs.reject { |key, _| key == :dependencies }

    if filtered_kwargs.empty? # https://bugs.ruby-lang.org/issues/14415
      super(*args, &block)
    else
      super(*args, **filtered_kwargs, &block)
    end
  end
end

Method Summary

Methods included from InheritanceCallback

#extended, #included