dry-system 0.18.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +93 -0
 - data/LICENSE +1 -1
 - data/README.md +1 -1
 - data/dry-system.gemspec +3 -4
 - data/lib/dry/system/auto_registrar.rb +16 -58
 - data/lib/dry/system/booter.rb +34 -15
 - data/lib/dry/system/component.rb +56 -94
 - data/lib/dry/system/component_dir.rb +128 -0
 - data/lib/dry/system/config/component_dir.rb +202 -0
 - data/lib/dry/system/config/component_dirs.rb +184 -0
 - data/lib/dry/system/container.rb +78 -143
 - data/lib/dry/system/errors.rb +21 -12
 - data/lib/dry/system/identifier.rb +157 -0
 - data/lib/dry/system/loader.rb +40 -41
 - data/lib/dry/system/loader/autoloading.rb +26 -0
 - data/lib/dry/system/version.rb +1 -1
 - metadata +17 -27
 - data/lib/dry/system/auto_registrar/configuration.rb +0 -43
 
| 
         @@ -0,0 +1,128 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "pathname"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative "constants"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "identifier"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative "magic_comments_parser"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Dry
         
     | 
| 
      
 7 
     | 
    
         
            +
              module System
         
     | 
| 
      
 8 
     | 
    
         
            +
                # A configured component directory within the container's root. Provides access to the
         
     | 
| 
      
 9 
     | 
    
         
            +
                # component directory's configuration, as well as methods for locating component files
         
     | 
| 
      
 10 
     | 
    
         
            +
                # within the directory
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                # @see Dry::System::Config::ComponentDir
         
     | 
| 
      
 13 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 14 
     | 
    
         
            +
                class ComponentDir
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @!attribute [r] config
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   @return [Dry::System::Config::ComponentDir] the component directory configuration
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #   @api private
         
     | 
| 
      
 18 
     | 
    
         
            +
                  attr_reader :config
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  # @!attribute [r] container
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #   @return [Dry::System::Container] the container managing the component directory
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   @api private
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attr_reader :container
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def initialize(config:, container:)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @config = config
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @container = container
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # Returns a component for a given identifier if a matching component file could be
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # found within the component dir
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # This will search within the component dir's configured default_namespace first,
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # then fall back to searching for a non-namespaced file
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # @param identifier [String] the identifier string
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # @return [Dry::System::Component, nil] the component, if found
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 41 
     | 
    
         
            +
                  def component_for_identifier(identifier)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    identifier = Identifier.new(
         
     | 
| 
      
 43 
     | 
    
         
            +
                      identifier,
         
     | 
| 
      
 44 
     | 
    
         
            +
                      namespace: default_namespace,
         
     | 
| 
      
 45 
     | 
    
         
            +
                      separator: container.config.namespace_separator
         
     | 
| 
      
 46 
     | 
    
         
            +
                    )
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    if (file_path = find_component_file(identifier.path))
         
     | 
| 
      
 49 
     | 
    
         
            +
                      return build_component(identifier, file_path)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    identifier = identifier.with(namespace: nil)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    if (file_path = find_component_file(identifier.path))
         
     | 
| 
      
 54 
     | 
    
         
            +
                      build_component(identifier, file_path)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  # Returns a component for a full path to a Ruby source file within the component dir
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # @param path [String] the full path to the file
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # @return [Dry::System::Component] the component
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 64 
     | 
    
         
            +
                  def component_for_path(path)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    separator = container.config.namespace_separator
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                    key = Pathname(path).relative_path_from(full_path).to_s
         
     | 
| 
      
 68 
     | 
    
         
            +
                      .sub(RB_EXT, EMPTY_STRING)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      .scan(WORD_REGEX)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      .join(separator)
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    identifier = Identifier.new(key, separator: separator)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    if identifier.start_with?(default_namespace)
         
     | 
| 
      
 75 
     | 
    
         
            +
                      identifier = identifier.dequalified(default_namespace, namespace: default_namespace)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    build_component(identifier, path)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  # Returns the full path of the component directory
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # @return [Pathname]
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def full_path
         
     | 
| 
      
 86 
     | 
    
         
            +
                    container.root.join(path)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 90 
     | 
    
         
            +
                  def component_options
         
     | 
| 
      
 91 
     | 
    
         
            +
                    {
         
     | 
| 
      
 92 
     | 
    
         
            +
                      auto_register: auto_register,
         
     | 
| 
      
 93 
     | 
    
         
            +
                      loader: loader,
         
     | 
| 
      
 94 
     | 
    
         
            +
                      memoize: memoize
         
     | 
| 
      
 95 
     | 
    
         
            +
                    }
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  private
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  def build_component(identifier, file_path)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    options = {
         
     | 
| 
      
 102 
     | 
    
         
            +
                      inflector: container.config.inflector,
         
     | 
| 
      
 103 
     | 
    
         
            +
                      **component_options,
         
     | 
| 
      
 104 
     | 
    
         
            +
                      **MagicCommentsParser.(file_path)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    }
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    Component.new(identifier, file_path: file_path, **options)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  def find_component_file(component_path)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    component_file = full_path.join("#{component_path}#{RB_EXT}")
         
     | 
| 
      
 112 
     | 
    
         
            +
                    component_file if component_file.exist?
         
     | 
| 
      
 113 
     | 
    
         
            +
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  def method_missing(name, *args, &block)
         
     | 
| 
      
 116 
     | 
    
         
            +
                    if config.respond_to?(name)
         
     | 
| 
      
 117 
     | 
    
         
            +
                      config.public_send(name, *args, &block)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    else
         
     | 
| 
      
 119 
     | 
    
         
            +
                      super
         
     | 
| 
      
 120 
     | 
    
         
            +
                    end
         
     | 
| 
      
 121 
     | 
    
         
            +
                  end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  def respond_to_missing?(name, include_all = false)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    config.respond_to?(name) || super
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,202 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "dry/configurable"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "dry/system/loader"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Dry
         
     | 
| 
      
 5 
     | 
    
         
            +
              module System
         
     | 
| 
      
 6 
     | 
    
         
            +
                module Config
         
     | 
| 
      
 7 
     | 
    
         
            +
                  class ComponentDir
         
     | 
| 
      
 8 
     | 
    
         
            +
                    include Dry::Configurable
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    # @!group Settings
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    # @!method auto_register=(policy)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    #
         
     | 
| 
      
 14 
     | 
    
         
            +
                    #   Sets the auto-registration policy for the component dir.
         
     | 
| 
      
 15 
     | 
    
         
            +
                    #
         
     | 
| 
      
 16 
     | 
    
         
            +
                    #   This may be a simple boolean to enable or disable auto-registration for all
         
     | 
| 
      
 17 
     | 
    
         
            +
                    #   components, or a proc accepting a `Dry::Sytem::Component` and returning a
         
     | 
| 
      
 18 
     | 
    
         
            +
                    #   boolean to configure auto-registration on a per-component basis
         
     | 
| 
      
 19 
     | 
    
         
            +
                    #
         
     | 
| 
      
 20 
     | 
    
         
            +
                    #   Defaults to `true`.
         
     | 
| 
      
 21 
     | 
    
         
            +
                    #
         
     | 
| 
      
 22 
     | 
    
         
            +
                    #   @param policy [Boolean, Proc]
         
     | 
| 
      
 23 
     | 
    
         
            +
                    #   @return [Boolean, Proc]
         
     | 
| 
      
 24 
     | 
    
         
            +
                    #
         
     | 
| 
      
 25 
     | 
    
         
            +
                    #   @example
         
     | 
| 
      
 26 
     | 
    
         
            +
                    #     dir.auto_register = false
         
     | 
| 
      
 27 
     | 
    
         
            +
                    #
         
     | 
| 
      
 28 
     | 
    
         
            +
                    #   @example
         
     | 
| 
      
 29 
     | 
    
         
            +
                    #     dir.auto_register = proc do |component|
         
     | 
| 
      
 30 
     | 
    
         
            +
                    #       !component.start_with?("entities")
         
     | 
| 
      
 31 
     | 
    
         
            +
                    #     end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    #
         
     | 
| 
      
 33 
     | 
    
         
            +
                    #   @see auto_register
         
     | 
| 
      
 34 
     | 
    
         
            +
                    #   @see Component
         
     | 
| 
      
 35 
     | 
    
         
            +
                    #
         
     | 
| 
      
 36 
     | 
    
         
            +
                    # @!method auto_register
         
     | 
| 
      
 37 
     | 
    
         
            +
                    #
         
     | 
| 
      
 38 
     | 
    
         
            +
                    #   Returns the configured auto-registration policy.
         
     | 
| 
      
 39 
     | 
    
         
            +
                    #
         
     | 
| 
      
 40 
     | 
    
         
            +
                    #   @return [Boolean, Proc] the configured policy
         
     | 
| 
      
 41 
     | 
    
         
            +
                    #
         
     | 
| 
      
 42 
     | 
    
         
            +
                    #   @see auto_register=
         
     | 
| 
      
 43 
     | 
    
         
            +
                    setting :auto_register, true
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    # @!method add_to_load_path=(policy)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    #
         
     | 
| 
      
 47 
     | 
    
         
            +
                    #   Sets whether the dir should be added to the `$LOAD_PATH` after the container
         
     | 
| 
      
 48 
     | 
    
         
            +
                    #   is configured.
         
     | 
| 
      
 49 
     | 
    
         
            +
                    #
         
     | 
| 
      
 50 
     | 
    
         
            +
                    #   Defaults to `true`. This may need to be set to `false` when using a class
         
     | 
| 
      
 51 
     | 
    
         
            +
                    #   autoloading system.
         
     | 
| 
      
 52 
     | 
    
         
            +
                    #
         
     | 
| 
      
 53 
     | 
    
         
            +
                    #   @param policy [Boolean]
         
     | 
| 
      
 54 
     | 
    
         
            +
                    #   @return [Boolean]
         
     | 
| 
      
 55 
     | 
    
         
            +
                    #
         
     | 
| 
      
 56 
     | 
    
         
            +
                    #   @see add_to_load_path
         
     | 
| 
      
 57 
     | 
    
         
            +
                    #   @see Container.configure
         
     | 
| 
      
 58 
     | 
    
         
            +
                    #
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # @!method add_to_load_path
         
     | 
| 
      
 60 
     | 
    
         
            +
                    #
         
     | 
| 
      
 61 
     | 
    
         
            +
                    #   Returns the configured value.
         
     | 
| 
      
 62 
     | 
    
         
            +
                    #
         
     | 
| 
      
 63 
     | 
    
         
            +
                    #   @return [Boolean]
         
     | 
| 
      
 64 
     | 
    
         
            +
                    #
         
     | 
| 
      
 65 
     | 
    
         
            +
                    #   @see add_to_load_path=
         
     | 
| 
      
 66 
     | 
    
         
            +
                    setting :add_to_load_path, true
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    # @!method default_namespace=(leading_namespace)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    #
         
     | 
| 
      
 70 
     | 
    
         
            +
                    #   Sets the leading namespace segments to be stripped when registering components
         
     | 
| 
      
 71 
     | 
    
         
            +
                    #   from the dir in the container.
         
     | 
| 
      
 72 
     | 
    
         
            +
                    #
         
     | 
| 
      
 73 
     | 
    
         
            +
                    #   This is useful to configure when the dir contains components in a module
         
     | 
| 
      
 74 
     | 
    
         
            +
                    #   namespace that you don't want repeated in their identifiers.
         
     | 
| 
      
 75 
     | 
    
         
            +
                    #
         
     | 
| 
      
 76 
     | 
    
         
            +
                    #   Defaults to `nil`.
         
     | 
| 
      
 77 
     | 
    
         
            +
                    #
         
     | 
| 
      
 78 
     | 
    
         
            +
                    #   @param leading_namespace [String, nil]
         
     | 
| 
      
 79 
     | 
    
         
            +
                    #   @return [String, nil]
         
     | 
| 
      
 80 
     | 
    
         
            +
                    #
         
     | 
| 
      
 81 
     | 
    
         
            +
                    #   @example
         
     | 
| 
      
 82 
     | 
    
         
            +
                    #     dir.default_namespace = "my_app"
         
     | 
| 
      
 83 
     | 
    
         
            +
                    #
         
     | 
| 
      
 84 
     | 
    
         
            +
                    #   @example
         
     | 
| 
      
 85 
     | 
    
         
            +
                    #     dir.default_namespace = "my_app.admin"
         
     | 
| 
      
 86 
     | 
    
         
            +
                    #
         
     | 
| 
      
 87 
     | 
    
         
            +
                    #   @see default_namespace
         
     | 
| 
      
 88 
     | 
    
         
            +
                    #
         
     | 
| 
      
 89 
     | 
    
         
            +
                    # @!method default_namespace
         
     | 
| 
      
 90 
     | 
    
         
            +
                    #
         
     | 
| 
      
 91 
     | 
    
         
            +
                    #   Returns the configured value.
         
     | 
| 
      
 92 
     | 
    
         
            +
                    #
         
     | 
| 
      
 93 
     | 
    
         
            +
                    #   @return [String, nil]
         
     | 
| 
      
 94 
     | 
    
         
            +
                    #
         
     | 
| 
      
 95 
     | 
    
         
            +
                    #   @see default_namespace=
         
     | 
| 
      
 96 
     | 
    
         
            +
                    setting :default_namespace
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                    # @!method loader=(loader)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    #
         
     | 
| 
      
 100 
     | 
    
         
            +
                    #   Sets the loader to use when registering coponents from the dir in the container.
         
     | 
| 
      
 101 
     | 
    
         
            +
                    #
         
     | 
| 
      
 102 
     | 
    
         
            +
                    #   Defaults to `Dry::System::Loader`.
         
     | 
| 
      
 103 
     | 
    
         
            +
                    #
         
     | 
| 
      
 104 
     | 
    
         
            +
                    #   When using a class autoloader, consider using `Dry::System::Loader::Autoloading`
         
     | 
| 
      
 105 
     | 
    
         
            +
                    #
         
     | 
| 
      
 106 
     | 
    
         
            +
                    #   @param loader [#call] the loader
         
     | 
| 
      
 107 
     | 
    
         
            +
                    #   @return [#call] the configured loader
         
     | 
| 
      
 108 
     | 
    
         
            +
                    #
         
     | 
| 
      
 109 
     | 
    
         
            +
                    #   @see loader
         
     | 
| 
      
 110 
     | 
    
         
            +
                    #   @see Loader
         
     | 
| 
      
 111 
     | 
    
         
            +
                    #   @see Loader::Autoloading
         
     | 
| 
      
 112 
     | 
    
         
            +
                    #
         
     | 
| 
      
 113 
     | 
    
         
            +
                    # @!method loader
         
     | 
| 
      
 114 
     | 
    
         
            +
                    #
         
     | 
| 
      
 115 
     | 
    
         
            +
                    #   Returns the configured loader.
         
     | 
| 
      
 116 
     | 
    
         
            +
                    #
         
     | 
| 
      
 117 
     | 
    
         
            +
                    #   @return [#call]
         
     | 
| 
      
 118 
     | 
    
         
            +
                    #
         
     | 
| 
      
 119 
     | 
    
         
            +
                    #   @see loader=
         
     | 
| 
      
 120 
     | 
    
         
            +
                    setting :loader, Dry::System::Loader
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                    # @!method memoize=(policy)
         
     | 
| 
      
 123 
     | 
    
         
            +
                    #
         
     | 
| 
      
 124 
     | 
    
         
            +
                    #   Sets whether to memoize components from the dir when registered in the
         
     | 
| 
      
 125 
     | 
    
         
            +
                    #   container.
         
     | 
| 
      
 126 
     | 
    
         
            +
                    #
         
     | 
| 
      
 127 
     | 
    
         
            +
                    #   This may be a simple boolean to enable or disable memoization for all
         
     | 
| 
      
 128 
     | 
    
         
            +
                    #   components, or a proc accepting a `Dry::Sytem::Component` and returning a
         
     | 
| 
      
 129 
     | 
    
         
            +
                    #   boolean to configure memoization on a per-component basis
         
     | 
| 
      
 130 
     | 
    
         
            +
                    #
         
     | 
| 
      
 131 
     | 
    
         
            +
                    #   Defaults to `false`.
         
     | 
| 
      
 132 
     | 
    
         
            +
                    #
         
     | 
| 
      
 133 
     | 
    
         
            +
                    #   @param policy [Boolean, Proc]
         
     | 
| 
      
 134 
     | 
    
         
            +
                    #   @return [Boolean, Proc] the configured memoization policy
         
     | 
| 
      
 135 
     | 
    
         
            +
                    #
         
     | 
| 
      
 136 
     | 
    
         
            +
                    #   @example
         
     | 
| 
      
 137 
     | 
    
         
            +
                    #     dir.memoize = true
         
     | 
| 
      
 138 
     | 
    
         
            +
                    #
         
     | 
| 
      
 139 
     | 
    
         
            +
                    #   @example
         
     | 
| 
      
 140 
     | 
    
         
            +
                    #     dir.memoize = proc do |component|
         
     | 
| 
      
 141 
     | 
    
         
            +
                    #       !component.start_with?("providers")
         
     | 
| 
      
 142 
     | 
    
         
            +
                    #     end
         
     | 
| 
      
 143 
     | 
    
         
            +
                    #
         
     | 
| 
      
 144 
     | 
    
         
            +
                    #   @see memoize
         
     | 
| 
      
 145 
     | 
    
         
            +
                    #   @see Component
         
     | 
| 
      
 146 
     | 
    
         
            +
                    #
         
     | 
| 
      
 147 
     | 
    
         
            +
                    # @!method memoize
         
     | 
| 
      
 148 
     | 
    
         
            +
                    #
         
     | 
| 
      
 149 
     | 
    
         
            +
                    #   Returns the configured memoization policy.
         
     | 
| 
      
 150 
     | 
    
         
            +
                    #
         
     | 
| 
      
 151 
     | 
    
         
            +
                    #   @return [Boolean, Proc] the configured memoization policy
         
     | 
| 
      
 152 
     | 
    
         
            +
                    #
         
     | 
| 
      
 153 
     | 
    
         
            +
                    #   @see memoize=
         
     | 
| 
      
 154 
     | 
    
         
            +
                    setting :memoize, false
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                    # @!endgroup
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                    # Returns the component dir path, relative to the configured container root
         
     | 
| 
      
 159 
     | 
    
         
            +
                    #
         
     | 
| 
      
 160 
     | 
    
         
            +
                    # @return [String] the path
         
     | 
| 
      
 161 
     | 
    
         
            +
                    attr_reader :path
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 164 
     | 
    
         
            +
                    def initialize(path)
         
     | 
| 
      
 165 
     | 
    
         
            +
                      super()
         
     | 
| 
      
 166 
     | 
    
         
            +
                      @path = path
         
     | 
| 
      
 167 
     | 
    
         
            +
                      yield self if block_given?
         
     | 
| 
      
 168 
     | 
    
         
            +
                    end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 171 
     | 
    
         
            +
                    def auto_register?
         
     | 
| 
      
 172 
     | 
    
         
            +
                      !!config.auto_register
         
     | 
| 
      
 173 
     | 
    
         
            +
                    end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    # Returns true if a setting has been explicitly configured and is not returning
         
     | 
| 
      
 176 
     | 
    
         
            +
                    # just a default value.
         
     | 
| 
      
 177 
     | 
    
         
            +
                    #
         
     | 
| 
      
 178 
     | 
    
         
            +
                    # This is used to determine which settings from `ComponentDirs` should be applied
         
     | 
| 
      
 179 
     | 
    
         
            +
                    # as additional defaults.
         
     | 
| 
      
 180 
     | 
    
         
            +
                    #
         
     | 
| 
      
 181 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 182 
     | 
    
         
            +
                    def configured?(key)
         
     | 
| 
      
 183 
     | 
    
         
            +
                      config._settings[key].input_defined?
         
     | 
| 
      
 184 
     | 
    
         
            +
                    end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                    private
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                    def method_missing(name, *args, &block)
         
     | 
| 
      
 189 
     | 
    
         
            +
                      if config.respond_to?(name)
         
     | 
| 
      
 190 
     | 
    
         
            +
                        config.public_send(name, *args, &block)
         
     | 
| 
      
 191 
     | 
    
         
            +
                      else
         
     | 
| 
      
 192 
     | 
    
         
            +
                        super
         
     | 
| 
      
 193 
     | 
    
         
            +
                      end
         
     | 
| 
      
 194 
     | 
    
         
            +
                    end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                    def respond_to_missing?(name, include_all = false)
         
     | 
| 
      
 197 
     | 
    
         
            +
                      config.respond_to?(name) || super
         
     | 
| 
      
 198 
     | 
    
         
            +
                    end
         
     | 
| 
      
 199 
     | 
    
         
            +
                  end
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,184 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "concurrent/map"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "dry/configurable"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "dry/system/constants"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "dry/system/errors"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative "component_dir"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Dry
         
     | 
| 
      
 8 
     | 
    
         
            +
              module System
         
     | 
| 
      
 9 
     | 
    
         
            +
                module Config
         
     | 
| 
      
 10 
     | 
    
         
            +
                  class ComponentDirs
         
     | 
| 
      
 11 
     | 
    
         
            +
                    include Dry::Configurable
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    # Settings from ComponentDir are configured here as defaults for all added dirs
         
     | 
| 
      
 14 
     | 
    
         
            +
                    ComponentDir._settings.each do |setting|
         
     | 
| 
      
 15 
     | 
    
         
            +
                      _settings << setting.dup
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    # @!group Settings
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    # @!method auto_register=(value)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    #
         
     | 
| 
      
 22 
     | 
    
         
            +
                    #   Sets a default `auto_register` for all added component dirs
         
     | 
| 
      
 23 
     | 
    
         
            +
                    #
         
     | 
| 
      
 24 
     | 
    
         
            +
                    #   @see ComponentDir.auto_register
         
     | 
| 
      
 25 
     | 
    
         
            +
                    #   @see auto_register
         
     | 
| 
      
 26 
     | 
    
         
            +
                    #
         
     | 
| 
      
 27 
     | 
    
         
            +
                    # @!method auto_register
         
     | 
| 
      
 28 
     | 
    
         
            +
                    #
         
     | 
| 
      
 29 
     | 
    
         
            +
                    #   Returns the configured default `auto_register`
         
     | 
| 
      
 30 
     | 
    
         
            +
                    #
         
     | 
| 
      
 31 
     | 
    
         
            +
                    #   @see auto_register=
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    # @!method add_to_load_path=(value)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    #
         
     | 
| 
      
 35 
     | 
    
         
            +
                    #   Sets a default `add_to_load_path` value for all added component dirs
         
     | 
| 
      
 36 
     | 
    
         
            +
                    #
         
     | 
| 
      
 37 
     | 
    
         
            +
                    #   @see ComponentDir.add_to_load_path
         
     | 
| 
      
 38 
     | 
    
         
            +
                    #   @see add_to_load_path
         
     | 
| 
      
 39 
     | 
    
         
            +
                    #
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # @!method add_to_load_path
         
     | 
| 
      
 41 
     | 
    
         
            +
                    #
         
     | 
| 
      
 42 
     | 
    
         
            +
                    #   Returns the configured default `add_to_load_path`
         
     | 
| 
      
 43 
     | 
    
         
            +
                    #
         
     | 
| 
      
 44 
     | 
    
         
            +
                    #   @see add_to_load_path=
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    # @!method default_namespace=(value)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    #
         
     | 
| 
      
 48 
     | 
    
         
            +
                    #   Sets a default `default_namespace` value for all added component dirs
         
     | 
| 
      
 49 
     | 
    
         
            +
                    #
         
     | 
| 
      
 50 
     | 
    
         
            +
                    #   @see ComponentDir.default_namespace
         
     | 
| 
      
 51 
     | 
    
         
            +
                    #   @see default_namespace
         
     | 
| 
      
 52 
     | 
    
         
            +
                    #
         
     | 
| 
      
 53 
     | 
    
         
            +
                    # @!method default_namespace
         
     | 
| 
      
 54 
     | 
    
         
            +
                    #
         
     | 
| 
      
 55 
     | 
    
         
            +
                    #   Returns the configured default `default_namespace`
         
     | 
| 
      
 56 
     | 
    
         
            +
                    #
         
     | 
| 
      
 57 
     | 
    
         
            +
                    #   @see default_namespace=
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    # @!method loader=(value)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    #
         
     | 
| 
      
 61 
     | 
    
         
            +
                    #   Sets a default `loader` value for all added component dirs
         
     | 
| 
      
 62 
     | 
    
         
            +
                    #
         
     | 
| 
      
 63 
     | 
    
         
            +
                    #   @see ComponentDir.loader
         
     | 
| 
      
 64 
     | 
    
         
            +
                    #   @see loader
         
     | 
| 
      
 65 
     | 
    
         
            +
                    #
         
     | 
| 
      
 66 
     | 
    
         
            +
                    # @!method loader
         
     | 
| 
      
 67 
     | 
    
         
            +
                    #
         
     | 
| 
      
 68 
     | 
    
         
            +
                    #   Returns the configured default `loader`
         
     | 
| 
      
 69 
     | 
    
         
            +
                    #
         
     | 
| 
      
 70 
     | 
    
         
            +
                    #   @see loader=
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    # @!method memoize=(value)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    #
         
     | 
| 
      
 74 
     | 
    
         
            +
                    #   Sets a default `memoize` value for all added component dirs
         
     | 
| 
      
 75 
     | 
    
         
            +
                    #
         
     | 
| 
      
 76 
     | 
    
         
            +
                    #   @see ComponentDir.memoize
         
     | 
| 
      
 77 
     | 
    
         
            +
                    #   @see memoize
         
     | 
| 
      
 78 
     | 
    
         
            +
                    #
         
     | 
| 
      
 79 
     | 
    
         
            +
                    # @!method memoize
         
     | 
| 
      
 80 
     | 
    
         
            +
                    #
         
     | 
| 
      
 81 
     | 
    
         
            +
                    #   Returns the configured default `memoize`
         
     | 
| 
      
 82 
     | 
    
         
            +
                    #
         
     | 
| 
      
 83 
     | 
    
         
            +
                    #   @see memoize=
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    # @!endgroup
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 88 
     | 
    
         
            +
                    def initialize
         
     | 
| 
      
 89 
     | 
    
         
            +
                      @dirs = Concurrent::Map.new
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 93 
     | 
    
         
            +
                    def initialize_copy(source)
         
     | 
| 
      
 94 
     | 
    
         
            +
                      super
         
     | 
| 
      
 95 
     | 
    
         
            +
                      @dirs = source.dirs.dup
         
     | 
| 
      
 96 
     | 
    
         
            +
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                    # Adds and configures a component dir
         
     | 
| 
      
 99 
     | 
    
         
            +
                    #
         
     | 
| 
      
 100 
     | 
    
         
            +
                    # @param path [String] the path for the component dir, relative to the configured
         
     | 
| 
      
 101 
     | 
    
         
            +
                    #   container root
         
     | 
| 
      
 102 
     | 
    
         
            +
                    #
         
     | 
| 
      
 103 
     | 
    
         
            +
                    # @yieldparam dir [ComponentDir] the component dir to configure
         
     | 
| 
      
 104 
     | 
    
         
            +
                    #
         
     | 
| 
      
 105 
     | 
    
         
            +
                    # @return [ComponentDir] the added component dir
         
     | 
| 
      
 106 
     | 
    
         
            +
                    #
         
     | 
| 
      
 107 
     | 
    
         
            +
                    # @example
         
     | 
| 
      
 108 
     | 
    
         
            +
                    #   component_dirs.add "lib" do |dir|
         
     | 
| 
      
 109 
     | 
    
         
            +
                    #     dir.default_namespace = "my_app"
         
     | 
| 
      
 110 
     | 
    
         
            +
                    #   end
         
     | 
| 
      
 111 
     | 
    
         
            +
                    #
         
     | 
| 
      
 112 
     | 
    
         
            +
                    # @see ComponentDir
         
     | 
| 
      
 113 
     | 
    
         
            +
                    def add(path)
         
     | 
| 
      
 114 
     | 
    
         
            +
                      raise ComponentDirAlreadyAddedError, path if dirs.key?(path)
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                      dirs[path] = ComponentDir.new(path).tap do |dir|
         
     | 
| 
      
 117 
     | 
    
         
            +
                        apply_defaults_to_dir(dir)
         
     | 
| 
      
 118 
     | 
    
         
            +
                        yield dir if block_given?
         
     | 
| 
      
 119 
     | 
    
         
            +
                      end
         
     | 
| 
      
 120 
     | 
    
         
            +
                    end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                    # Returns the added component dirs, with default settings applied
         
     | 
| 
      
 123 
     | 
    
         
            +
                    #
         
     | 
| 
      
 124 
     | 
    
         
            +
                    # @return [Hash<String, ComponentDir>] the component dirs as a hash, keyed by path
         
     | 
| 
      
 125 
     | 
    
         
            +
                    def dirs
         
     | 
| 
      
 126 
     | 
    
         
            +
                      @dirs.each { |_, dir| apply_defaults_to_dir(dir) }
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                    # Returns the added component dirs, with default settings applied
         
     | 
| 
      
 130 
     | 
    
         
            +
                    #
         
     | 
| 
      
 131 
     | 
    
         
            +
                    # @return [Array<ComponentDir>]
         
     | 
| 
      
 132 
     | 
    
         
            +
                    def to_a
         
     | 
| 
      
 133 
     | 
    
         
            +
                      dirs.values
         
     | 
| 
      
 134 
     | 
    
         
            +
                    end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                    # Calls the given block once for each added component dir, passing the dir as an
         
     | 
| 
      
 137 
     | 
    
         
            +
                    # argument.
         
     | 
| 
      
 138 
     | 
    
         
            +
                    #
         
     | 
| 
      
 139 
     | 
    
         
            +
                    # @yieldparam dir [ComponentDir] the yielded component dir
         
     | 
| 
      
 140 
     | 
    
         
            +
                    def each(&block)
         
     | 
| 
      
 141 
     | 
    
         
            +
                      to_a.each(&block)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    private
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                    # Apply default settings to a component dir. This is run every time the dirs are
         
     | 
| 
      
 147 
     | 
    
         
            +
                    # accessed to ensure defaults are applied regardless of when new component dirs
         
     | 
| 
      
 148 
     | 
    
         
            +
                    # are added. This method must be idempotent.
         
     | 
| 
      
 149 
     | 
    
         
            +
                    #
         
     | 
| 
      
 150 
     | 
    
         
            +
                    # @return [void]
         
     | 
| 
      
 151 
     | 
    
         
            +
                    def apply_defaults_to_dir(dir)
         
     | 
| 
      
 152 
     | 
    
         
            +
                      dir.config.values.each do |key, _value|
         
     | 
| 
      
 153 
     | 
    
         
            +
                        if configured?(key) && !dir.configured?(key)
         
     | 
| 
      
 154 
     | 
    
         
            +
                          dir.public_send(:"#{key}=", public_send(key))
         
     | 
| 
      
 155 
     | 
    
         
            +
                        end
         
     | 
| 
      
 156 
     | 
    
         
            +
                      end
         
     | 
| 
      
 157 
     | 
    
         
            +
                    end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                    # Returns true if a setting has been explicitly configured and is not returning
         
     | 
| 
      
 160 
     | 
    
         
            +
                    # just a default value.
         
     | 
| 
      
 161 
     | 
    
         
            +
                    #
         
     | 
| 
      
 162 
     | 
    
         
            +
                    # This is used to determine which settings should be applied to added component
         
     | 
| 
      
 163 
     | 
    
         
            +
                    # dirs as additional defaults.
         
     | 
| 
      
 164 
     | 
    
         
            +
                    #
         
     | 
| 
      
 165 
     | 
    
         
            +
                    # @api private
         
     | 
| 
      
 166 
     | 
    
         
            +
                    def configured?(key)
         
     | 
| 
      
 167 
     | 
    
         
            +
                      config._settings[key].input_defined?
         
     | 
| 
      
 168 
     | 
    
         
            +
                    end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    def method_missing(name, *args, &block)
         
     | 
| 
      
 171 
     | 
    
         
            +
                      if config.respond_to?(name)
         
     | 
| 
      
 172 
     | 
    
         
            +
                        config.public_send(name, *args, &block)
         
     | 
| 
      
 173 
     | 
    
         
            +
                      else
         
     | 
| 
      
 174 
     | 
    
         
            +
                        super
         
     | 
| 
      
 175 
     | 
    
         
            +
                      end
         
     | 
| 
      
 176 
     | 
    
         
            +
                    end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                    def respond_to_missing?(name, include_all = false)
         
     | 
| 
      
 179 
     | 
    
         
            +
                      config.respond_to?(name) || super
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
      
 181 
     | 
    
         
            +
                  end
         
     | 
| 
      
 182 
     | 
    
         
            +
                end
         
     | 
| 
      
 183 
     | 
    
         
            +
              end
         
     | 
| 
      
 184 
     | 
    
         
            +
            end
         
     |