class DependencyManager::Factory

Base for all other factories, providing interface hints and generic functionality

### Initialize for Dependency Specifications

Every keyword argument used in the `initialize` function for a Factory is used to resolve the dependencies of the class with the exception of `CONTEXT_DEPENDENCIES`.

`:keyreq` represents a required argument, while `:key` represents an optional one:

“`ruby def initialize(logger:, optional_dependency: nil, **dependencies)

super(**dependencies)

@logger = logger
@optional_dependency = optional_dependency

end “`

This value could be `nil` or any other sane default value for the dependency specified.

The `Factory` implements several helper methods on its singleton class like `dependencies`, `optional_dependencies`, and `factory_dependencies` to help with constructing dependency chains.

Constants

CONTEXT_DEPENDENCIES

Dependencies that are always present and injected at a top level rather than by other factories

KEYWORD_ARGS

Keyword param types

OPTIONAL_ARG

Public Class Methods

const_name() click to toggle source
# File lib/dependency_manager/factory.rb, line 87
def const_name
  to_s.split('::').last
end
constantize(s) click to toggle source

Utility to constantize an underscored string or symbol

@param s [String, Symbol]

@return [Symbol]

# File lib/dependency_manager/factory.rb, line 83
def constantize(s)
  s.to_s.split('_').map(&:capitalize).join.to_sym
end
dependencies() click to toggle source

Dependencies of the class under the factory that it needs to initialize.

@return [Array]

# File lib/dependency_manager/factory.rb, line 112
def dependencies
  dependencies = parameters
    .select { |type, _name| KEYWORD_ARGS.include?(type) }
    .map(&:last)

  dependencies - CONTEXT_DEPENDENCIES
end
dependency_name() click to toggle source

Name of the expected dependency to be generated

@return [Symbol]

# File lib/dependency_manager/factory.rb, line 101
def dependency_name
  name.to_s.sub(/_factory$/, '').to_sym
end
factories() click to toggle source

Get all available factory names except the Base factory

@return [Array]

# File lib/dependency_manager/factory.rb, line 59
def factories
  @factories || Set.new
end
factory_dependencies() click to toggle source

Dependencies of the factory itself to make sure factories load in the correct order.

@return [Array]

# File lib/dependency_manager/factory.rb, line 124
def factory_dependencies
  dependencies.map { |d| "#{d}_factory".to_sym }
end
get(factory_name) click to toggle source

Get a factory by its underscored name

@param factory_name [Symbol]

@return [Symbol] Constant name

# File lib/dependency_manager/factory.rb, line 68
def get(factory_name)
  const_name = constantize(factory_name)

  unless const_defined?(const_name)
    raise ArgumentError, "Tried to get non-existant Factory. Did you remember to define it?: #{const_name}"
  end

  const_get const_name
end
inherited(subclass) click to toggle source

Captures classes inheriting from Factory for later use

@param subclass [Class]

The subclass

@return [void]

# File lib/dependency_manager/factory.rb, line 51
def inherited(subclass)
  @factories ||= Set.new
  @factories.add subclass
end
name() click to toggle source

Name of the factory

@return [String]

# File lib/dependency_manager/factory.rb, line 94
def name
  underscore const_name
end
new(app_context: nil, factory_config:) click to toggle source

Creates a new Factory.

@param app_context: nil [AppContext]

Application context information. Defaulted to `nil` in case users
do not need this information.

@param factory_config: [Hash[Symbol, Any]]

Configuration specific to the factory

@return [Factory]

# File lib/dependency_manager/factory.rb, line 167
def initialize(app_context: nil, factory_config:)
  @app_context = app_context
  @factory_config = factory_config
end
optional_dependencies() click to toggle source

Optional arguments that are not strictly required, but used for additional functionality.

@return [Array]

# File lib/dependency_manager/factory.rb, line 139
def optional_dependencies
  optionals = parameters
    .select { |type, _name| type == OPTIONAL_ARG }
    .map(&:last)

  optionals - CONTEXT_DEPENDENCIES
end
parameters() click to toggle source
# File lib/dependency_manager/factory.rb, line 105
def parameters
  instance_method(:initialize).parameters
end
required_dependencies() click to toggle source

Dependencies required to build the factory

@return [Array]

# File lib/dependency_manager/factory.rb, line 131
def required_dependencies
  dependencies - optional_dependencies
end
underscore(const_name) click to toggle source

Underscores a constant name

@param const_name [Symbol]

@return [Symbol]

# File lib/dependency_manager/factory.rb, line 152
def underscore(const_name)
  const_name.gsub(/([^\^])([A-Z])/,'\1_\2').downcase.to_sym
end

Public Instance Methods

build() click to toggle source

Used to build the dependency

@raise [NotImplementedError]

# File lib/dependency_manager/factory.rb, line 175
def build
  raise NotImplementedError
end
configuration() click to toggle source

Used to generate configuration for the dependency, not always necessary for shorter builds.

As a default will be an alias for `@factory_config`, and is used as a hook point for any validation.

@raise [Hash[Symbol, Any]]

# File lib/dependency_manager/factory.rb, line 186
def configuration
  @configuration ||= deep_merge(default_configuration, @factory_config)
end
default_configuration() click to toggle source

Default configuration of the Factory

@return [Hash[Symbol, Any]]

# File lib/dependency_manager/factory.rb, line 193
def default_configuration
  {}
end
enabled?() click to toggle source

Whether or not the dependency should be enabled. It is suggested to use this as a guard when building dependencies:

“`ruby def build

return unless enabled?

# ...

end “`

@return [FalseClass] Disabled by default

# File lib/dependency_manager/factory.rb, line 216
def enabled?
  false
end
load_requirements() click to toggle source

Used to load and require any associated external dependencies.

@raise [NotImplementedError]

# File lib/dependency_manager/factory.rb, line 200
def load_requirements
  raise NotImplementedError
end

Protected Instance Methods

deep_merge(a, b, &fn) click to toggle source

Deeply merges two Hashes

@param a [Hash]

Original Hash

@param b [Hash]

Hash to merge

@param &fn [Proc[Any, Any, Any]]

Merging function

@return [Hash]

# File lib/dependency_manager/factory.rb, line 232
          def deep_merge(a, b, &fn)
  deep_merge!(a.dup, b.dup, &fn)
end
deep_merge!(a, b, &fn) click to toggle source

Destructive merge of two hashes

@param a [Hash]

Original Hash

@param b [Hash]

Hash to merge

@param &fn [Proc[Any, Any, Any]]

Merging function

@return [Hash]

# File lib/dependency_manager/factory.rb, line 248
          def deep_merge!(a, b, &fn)
  a.merge!(b) do |key, left, right|
    next deep_merge(left, right, &fn) if left.is_a?(Hash) && right.is_a?(Hash)
    next fn.call(left, right, &fn) if block_given?

    right
  end
end