- 
            
            
              
            
            
# frozen_string_literal: true
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
require "marameters"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
module Infusible
           
        
      
        
          
- 
            
            
              
            
            
  # Provides the automatic and complete resolution of all injected dependencies.
           
        
      
        
          
- 
            
            
              
            
            
  # :reek:TooManyInstanceVariables
           
        
      
        
          
- 
            
              1
            
            
              
            
            
  class Builder < Module
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def self.define_instance_variables target, keys, keywords
           
        
      
        
          
- 
            
              41
            
            
              
                
                  else: 4
                
              
                
                  then: 37
                
              
            
            
      unless target.instance_variable_defined? :@infused_keys
           
        
      
        
          
- 
            
              37
            
            
              
            
            
        target.instance_variable_set :@infused_keys, keys
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              41
            
            
              
            
            
      keys.each do |key|
           
        
      
        
          
- 
            
              72
            
            
              
                
                  else: 70
                
              
                
                  then: 2
                
              
            
            
        next unless keywords.key?(key) || !target.instance_variable_defined?(:"@#{key}")
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              70
            
            
              
            
            
        target.instance_variable_set :"@#{key}", keywords[key]
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    private_class_method :define_instance_variables
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def initialize container, *configuration, scope: :private
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      super()
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      @container = container
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      @dependencies = DependencyMap.new(*configuration)
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      @scope = scope
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      @class_module = Module.new
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      @instance_module = Module.new.set_temporary_name "infusible"
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              61
            
            
              
            
            
      freeze
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def included descendant
           
        
      
        
          
- 
            
              43
            
            
              
                
                  else: 42
                
              
                
                  then: 1
                
              
            
            
      unless descendant.is_a? Class
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        fail TypeError,
           
        
      
        
          
- 
            
            
              
            
            
             "Can only infuse a class, invalid object: #{descendant} (#{descendant.class})."
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      super
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      define descendant
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      descendant.extend class_module
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      descendant.include instance_module
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    attr_reader :container, :dependencies, :scope, :class_module, :instance_module
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def define descendant
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      define_new
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      define_initialize descendant
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      define_readers
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def define_new
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      class_module.module_exec container, dependencies.to_h do |container, collection|
           
        
      
        
          
- 
            
              42
            
            
              
            
            
        define_method :new do |*positionals, **keywords, &block|
           
        
      
        
          
- 
            
              113
            
            
              
                
                  else: 4
                
              
                
                  then: 68
                
              
            
            
          collection.each { |name, id| keywords[name] = container[id] unless keywords.key? name }
           
        
      
        
          
- 
            
              41
            
            
              
            
            
          super(*positionals, **keywords, &block)
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def define_initialize descendant
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      super_parameters = Marameters.of(descendant, :initialize).map do |instance|
           
        
      
        
          
- 
            
              45
            
            
              
                
                  else: 3
                
              
                
                  then: 42
                
              
            
            
        break instance unless instance.only_bare_splats?
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      variablizer = self.class.method :define_instance_variables
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              42
            
            
              
                
                  then: 3
                
              
            
            
      if super_parameters.positionals? || super_parameters.only_single_splats?
           
        
      
        
          
- 
            
              3
            
            
              
            
            
        define_initialize_with_positionals super_parameters, variablizer
           
        
      
        
          
- 
            
            
              
                
                  else: 39
                
              
            
            
      else
           
        
      
        
          
- 
            
              39
            
            
              
            
            
        define_initialize_with_keywords super_parameters, variablizer
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def define_initialize_with_positionals super_parameters, variablizer
           
        
      
        
          
- 
            
              3
            
            
              
            
            
      instance_module.module_exec dependencies.keys, variablizer do |keys, definer|
           
        
      
        
          
- 
            
              3
            
            
              
            
            
        define_method :initialize do |*positionals, **keywords, &block|
           
        
      
        
          
- 
            
              3
            
            
              
            
            
          definer.call self, keys, keywords
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              3
            
            
              
                
                  then: 1
                
              
            
            
          if super_parameters.only_single_splats?
           
        
      
        
          
- 
            
              1
            
            
              
            
            
            super(*positionals, **keywords, &block)
           
        
      
        
          
- 
            
            
              
                
                  else: 2
                
              
            
            
          else
           
        
      
        
          
- 
            
              2
            
            
              
            
            
            super(*positionals, **super_parameters.keywords_for(*keys, **keywords), &block)
           
        
      
        
          
- 
            
            
              
            
            
          end
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def define_initialize_with_keywords super_parameters, variablizer
           
        
      
        
          
- 
            
              39
            
            
              
            
            
      instance_module.module_exec dependencies.keys, variablizer do |keys, definer|
           
        
      
        
          
- 
            
              39
            
            
              
            
            
        define_method :initialize do |**keywords, &block|
           
        
      
        
          
- 
            
              38
            
            
              
            
            
          definer.call self, keys, keywords
           
        
      
        
          
- 
            
              38
            
            
              
            
            
          super(**super_parameters.keywords_for(*keys, **keywords), &block)
           
        
      
        
          
- 
            
            
              
            
            
        end
           
        
      
        
          
- 
            
            
              
            
            
      end
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              1
            
            
              
            
            
    def define_readers
           
        
      
        
          
- 
            
              116
            
            
              
            
            
      methods = dependencies.keys.map { |key| ":#{key}" }
           
        
      
        
          
- 
            
              42
            
            
              
                
                  then: 41
                
              
                
                  else: 1
                
              
            
            
      computed_scope = METHOD_SCOPES.include?(scope) ? scope : :private
           
        
      
        
          
- 
            
            
              
            
            
           
        
      
        
          
- 
            
              42
            
            
              
            
            
      instance_module.module_eval <<-READERS, __FILE__, __LINE__ + 1
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        attr_reader :infused_keys
           
        
      
        
          
- 
            
              1
            
            
              
            
            
        #{computed_scope} attr_reader #{methods.join ", "}
           
        
      
        
          
- 
            
            
              
            
            
      READERS
           
        
      
        
          
- 
            
            
              
            
            
    end
           
        
      
        
          
- 
            
            
              
            
            
  end
           
        
      
        
          
- 
            
            
              
            
            
end