dry-initializer 3.0.2
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 +7 -0
 - data/.codeclimate.yml +12 -0
 - data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
 - data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
 - data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
 - data/.github/workflows/custom_ci.yml +74 -0
 - data/.github/workflows/docsite.yml +34 -0
 - data/.github/workflows/sync_configs.yml +34 -0
 - data/.gitignore +12 -0
 - data/.rspec +4 -0
 - data/.rubocop.yml +89 -0
 - data/CHANGELOG.md +890 -0
 - data/CODE_OF_CONDUCT.md +13 -0
 - data/CONTRIBUTING.md +29 -0
 - data/Gemfile +38 -0
 - data/Guardfile +5 -0
 - data/LICENSE +20 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +89 -0
 - data/Rakefile +8 -0
 - data/benchmarks/compare_several_defaults.rb +82 -0
 - data/benchmarks/plain_options.rb +63 -0
 - data/benchmarks/plain_params.rb +84 -0
 - data/benchmarks/with_coercion.rb +71 -0
 - data/benchmarks/with_defaults.rb +66 -0
 - data/benchmarks/with_defaults_and_coercion.rb +59 -0
 - data/docsite/source/attributes.html.md +106 -0
 - data/docsite/source/container-version.html.md +39 -0
 - data/docsite/source/index.html.md +43 -0
 - data/docsite/source/inheritance.html.md +43 -0
 - data/docsite/source/optionals-and-defaults.html.md +130 -0
 - data/docsite/source/options-tolerance.html.md +27 -0
 - data/docsite/source/params-and-options.html.md +74 -0
 - data/docsite/source/rails-support.html.md +101 -0
 - data/docsite/source/readers.html.md +43 -0
 - data/docsite/source/skip-undefined.html.md +59 -0
 - data/docsite/source/type-constraints.html.md +160 -0
 - data/dry-initializer.gemspec +20 -0
 - data/lib/dry-initializer.rb +1 -0
 - data/lib/dry/initializer.rb +61 -0
 - data/lib/dry/initializer/builders.rb +7 -0
 - data/lib/dry/initializer/builders/attribute.rb +81 -0
 - data/lib/dry/initializer/builders/initializer.rb +61 -0
 - data/lib/dry/initializer/builders/reader.rb +50 -0
 - data/lib/dry/initializer/builders/signature.rb +32 -0
 - data/lib/dry/initializer/config.rb +184 -0
 - data/lib/dry/initializer/definition.rb +65 -0
 - data/lib/dry/initializer/dispatchers.rb +112 -0
 - data/lib/dry/initializer/dispatchers/build_nested_type.rb +59 -0
 - data/lib/dry/initializer/dispatchers/check_type.rb +43 -0
 - data/lib/dry/initializer/dispatchers/prepare_default.rb +40 -0
 - data/lib/dry/initializer/dispatchers/prepare_ivar.rb +12 -0
 - data/lib/dry/initializer/dispatchers/prepare_optional.rb +13 -0
 - data/lib/dry/initializer/dispatchers/prepare_reader.rb +30 -0
 - data/lib/dry/initializer/dispatchers/prepare_source.rb +28 -0
 - data/lib/dry/initializer/dispatchers/prepare_target.rb +44 -0
 - data/lib/dry/initializer/dispatchers/unwrap_type.rb +22 -0
 - data/lib/dry/initializer/dispatchers/wrap_type.rb +27 -0
 - data/lib/dry/initializer/dsl.rb +43 -0
 - data/lib/dry/initializer/mixin.rb +15 -0
 - data/lib/dry/initializer/mixin/local.rb +19 -0
 - data/lib/dry/initializer/mixin/root.rb +11 -0
 - data/lib/dry/initializer/struct.rb +39 -0
 - data/lib/dry/initializer/undefined.rb +2 -0
 - data/lib/tasks/benchmark.rake +41 -0
 - data/lib/tasks/profile.rake +78 -0
 - data/spec/attributes_spec.rb +38 -0
 - data/spec/coercion_of_nil_spec.rb +25 -0
 - data/spec/custom_dispatchers_spec.rb +35 -0
 - data/spec/custom_initializer_spec.rb +30 -0
 - data/spec/default_values_spec.rb +83 -0
 - data/spec/definition_spec.rb +111 -0
 - data/spec/invalid_default_spec.rb +13 -0
 - data/spec/list_type_spec.rb +32 -0
 - data/spec/missed_default_spec.rb +14 -0
 - data/spec/nested_type_spec.rb +48 -0
 - data/spec/optional_spec.rb +71 -0
 - data/spec/options_tolerance_spec.rb +11 -0
 - data/spec/public_attributes_utility_spec.rb +22 -0
 - data/spec/reader_spec.rb +87 -0
 - data/spec/repetitive_definitions_spec.rb +69 -0
 - data/spec/several_assignments_spec.rb +41 -0
 - data/spec/spec_helper.rb +29 -0
 - data/spec/subclassing_spec.rb +49 -0
 - data/spec/type_argument_spec.rb +35 -0
 - data/spec/type_constraint_spec.rb +78 -0
 - data/spec/value_coercion_via_dry_types_spec.rb +29 -0
 - metadata +209 -0
 
| 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Dry::Initializer
         
     | 
| 
      
 2 
     | 
    
         
            +
              #
         
     | 
| 
      
 3 
     | 
    
         
            +
              # @private
         
     | 
| 
      
 4 
     | 
    
         
            +
              # @abstract
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Base class for parameter or option definitions
         
     | 
| 
      
 7 
     | 
    
         
            +
              # Defines methods to add corresponding reader to the class,
         
     | 
| 
      
 8 
     | 
    
         
            +
              # and build value of instance attribute.
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
              class Definition
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_reader :option, :null, :source, :target, :ivar,
         
     | 
| 
      
 12 
     | 
    
         
            +
                            :type, :optional, :default, :reader,
         
     | 
| 
      
 13 
     | 
    
         
            +
                            :desc
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def options
         
     | 
| 
      
 16 
     | 
    
         
            +
                  {
         
     | 
| 
      
 17 
     | 
    
         
            +
                    as:       target,
         
     | 
| 
      
 18 
     | 
    
         
            +
                    type:     type,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    optional: optional,
         
     | 
| 
      
 20 
     | 
    
         
            +
                    default:  default,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    reader:   reader,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    desc:     desc
         
     | 
| 
      
 23 
     | 
    
         
            +
                  }.reject { |_, value| value.nil? }
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def name
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @name ||= (option ? "option" : "parameter") << " '#{source}'"
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                alias to_s    name
         
     | 
| 
      
 30 
     | 
    
         
            +
                alias to_str  name
         
     | 
| 
      
 31 
     | 
    
         
            +
                alias inspect name
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def ==(other)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  other.instance_of?(self.class) && (other.source == source)
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def code
         
     | 
| 
      
 38 
     | 
    
         
            +
                  Builders::Reader[self]
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def inch
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @inch ||= (option ? "@option" : "@param ").tap do |text|
         
     | 
| 
      
 43 
     | 
    
         
            +
                    text << " [Object]"
         
     | 
| 
      
 44 
     | 
    
         
            +
                    text << (option ? " :#{source}" : " #{source}")
         
     | 
| 
      
 45 
     | 
    
         
            +
                    text << (optional ? " (optional)" : " (required)")
         
     | 
| 
      
 46 
     | 
    
         
            +
                    text << " #{desc}" if desc
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                private
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def initialize(**options)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @option   = options[:option]
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @null     = options[:null]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @source   = options[:source]
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @target   = options[:target]
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @ivar     = "@#{@target}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @type     = options[:type]
         
     | 
| 
      
 59 
     | 
    
         
            +
                  @reader   = options[:reader]
         
     | 
| 
      
 60 
     | 
    
         
            +
                  @default  = options[:default]
         
     | 
| 
      
 61 
     | 
    
         
            +
                  @optional = options[:optional]
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @desc     = options[:desc]
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # The module is responsible for __normalizing__ arguments
         
     | 
| 
      
 3 
     | 
    
         
            +
            # of `.param` and `.option`.
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # What the module does is convert the source list of arguments
         
     | 
| 
      
 6 
     | 
    
         
            +
            # into the standard set of options:
         
     | 
| 
      
 7 
     | 
    
         
            +
            # - `:option`   -- whether an argument is an option (or param)
         
     | 
| 
      
 8 
     | 
    
         
            +
            # - `:source`   -- the name of source option
         
     | 
| 
      
 9 
     | 
    
         
            +
            # - `:target`   -- the target name of the reader
         
     | 
| 
      
 10 
     | 
    
         
            +
            # - `:reader`   -- if the reader's privacy (:public, :protected, :private, nil)
         
     | 
| 
      
 11 
     | 
    
         
            +
            # - `:ivar`     -- the target nane of the variable
         
     | 
| 
      
 12 
     | 
    
         
            +
            # - `:type`     -- the callable coercer of the source value
         
     | 
| 
      
 13 
     | 
    
         
            +
            # - `:optional` -- if the argument is optional
         
     | 
| 
      
 14 
     | 
    
         
            +
            # - `:default`  -- the proc returning the default value of the source value
         
     | 
| 
      
 15 
     | 
    
         
            +
            # - `:null`     -- the value to be set to unassigned optional argument
         
     | 
| 
      
 16 
     | 
    
         
            +
            #
         
     | 
| 
      
 17 
     | 
    
         
            +
            # It is this set is used to build [Dry::Initializer::Definition].
         
     | 
| 
      
 18 
     | 
    
         
            +
            #
         
     | 
| 
      
 19 
     | 
    
         
            +
            # @example
         
     | 
| 
      
 20 
     | 
    
         
            +
            #    # from `option :foo, [], as: :bar, optional: :true
         
     | 
| 
      
 21 
     | 
    
         
            +
            #    input = { name: :foo, as: :bar, type: [], optional: true }
         
     | 
| 
      
 22 
     | 
    
         
            +
            #
         
     | 
| 
      
 23 
     | 
    
         
            +
            #    Dry::Initializer::Dispatcher.call(input)
         
     | 
| 
      
 24 
     | 
    
         
            +
            #    # => {
         
     | 
| 
      
 25 
     | 
    
         
            +
            #    #      source:   "foo",
         
     | 
| 
      
 26 
     | 
    
         
            +
            #    #      target:   "bar",
         
     | 
| 
      
 27 
     | 
    
         
            +
            #    #      reader:   :public,
         
     | 
| 
      
 28 
     | 
    
         
            +
            #    #      ivar:     "@bar",
         
     | 
| 
      
 29 
     | 
    
         
            +
            #    #      type:  ->(v) { Array(v) } }, # simplified for brevity
         
     | 
| 
      
 30 
     | 
    
         
            +
            #    #      optional: true,
         
     | 
| 
      
 31 
     | 
    
         
            +
            #    #      default:  -> { Dry::Initializer::UNDEFINED },
         
     | 
| 
      
 32 
     | 
    
         
            +
            #    #    }
         
     | 
| 
      
 33 
     | 
    
         
            +
            #
         
     | 
| 
      
 34 
     | 
    
         
            +
            # # Settings
         
     | 
| 
      
 35 
     | 
    
         
            +
            #
         
     | 
| 
      
 36 
     | 
    
         
            +
            # The module uses global setting `null` to define what value
         
     | 
| 
      
 37 
     | 
    
         
            +
            # should be set to variables that kept unassigned. By default it
         
     | 
| 
      
 38 
     | 
    
         
            +
            # uses `Dry::Initializer::UNDEFINED`
         
     | 
| 
      
 39 
     | 
    
         
            +
            #
         
     | 
| 
      
 40 
     | 
    
         
            +
            # # Syntax Extensions
         
     | 
| 
      
 41 
     | 
    
         
            +
            #
         
     | 
| 
      
 42 
     | 
    
         
            +
            # The module supports syntax extensions. You can add any number
         
     | 
| 
      
 43 
     | 
    
         
            +
            # of custom dispatchers __on top__ of the stack of default dispatchers.
         
     | 
| 
      
 44 
     | 
    
         
            +
            # Every dispatcher should be a callable object that takes
         
     | 
| 
      
 45 
     | 
    
         
            +
            # the source set of options and converts it to another set of options.
         
     | 
| 
      
 46 
     | 
    
         
            +
            #
         
     | 
| 
      
 47 
     | 
    
         
            +
            # @example Add special dispatcher
         
     | 
| 
      
 48 
     | 
    
         
            +
            #
         
     | 
| 
      
 49 
     | 
    
         
            +
            #   # Define a dispatcher for key :integer
         
     | 
| 
      
 50 
     | 
    
         
            +
            #   dispatcher = proc do |integer: false, **opts|
         
     | 
| 
      
 51 
     | 
    
         
            +
            #     opts.merge(type: proc(&:to_i)) if integer
         
     | 
| 
      
 52 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 53 
     | 
    
         
            +
            #
         
     | 
| 
      
 54 
     | 
    
         
            +
            #   # Register a dispatcher
         
     | 
| 
      
 55 
     | 
    
         
            +
            #   Dry::Initializer::Dispatchers << dispatcher
         
     | 
| 
      
 56 
     | 
    
         
            +
            #
         
     | 
| 
      
 57 
     | 
    
         
            +
            #   # Now you can use option `integer: true` instead of `type: proc(&:to_i)`
         
     | 
| 
      
 58 
     | 
    
         
            +
            #   class Foo
         
     | 
| 
      
 59 
     | 
    
         
            +
            #     extend Dry::Initializer
         
     | 
| 
      
 60 
     | 
    
         
            +
            #     param :id, integer: true
         
     | 
| 
      
 61 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 62 
     | 
    
         
            +
            #
         
     | 
| 
      
 63 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers
         
     | 
| 
      
 64 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              # @!attribute [rw] null Defines a value to be set to unassigned attributes
         
     | 
| 
      
 67 
     | 
    
         
            +
              # @return [Object]
         
     | 
| 
      
 68 
     | 
    
         
            +
              attr_accessor :null
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
              #
         
     | 
| 
      
 71 
     | 
    
         
            +
              # Registers a new dispatcher
         
     | 
| 
      
 72 
     | 
    
         
            +
              #
         
     | 
| 
      
 73 
     | 
    
         
            +
              # @param [#call] dispatcher
         
     | 
| 
      
 74 
     | 
    
         
            +
              # @return [self] itself
         
     | 
| 
      
 75 
     | 
    
         
            +
              #
         
     | 
| 
      
 76 
     | 
    
         
            +
              def <<(dispatcher)
         
     | 
| 
      
 77 
     | 
    
         
            +
                @pipeline = [dispatcher] + pipeline
         
     | 
| 
      
 78 
     | 
    
         
            +
                self
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              #
         
     | 
| 
      
 82 
     | 
    
         
            +
              # Normalizes the source set of options
         
     | 
| 
      
 83 
     | 
    
         
            +
              #
         
     | 
| 
      
 84 
     | 
    
         
            +
              # @param [Hash<Symbol, Object>] options
         
     | 
| 
      
 85 
     | 
    
         
            +
              # @return [Hash<Symbol, Objct>] normalized set of options
         
     | 
| 
      
 86 
     | 
    
         
            +
              #
         
     | 
| 
      
 87 
     | 
    
         
            +
              def call(**options)
         
     | 
| 
      
 88 
     | 
    
         
            +
                options = { null: null, **options }
         
     | 
| 
      
 89 
     | 
    
         
            +
                pipeline.reduce(options) { |opts, dispatcher| dispatcher.call(**opts) }
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              private
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
              require_relative "dispatchers/build_nested_type"
         
     | 
| 
      
 95 
     | 
    
         
            +
              require_relative "dispatchers/check_type"
         
     | 
| 
      
 96 
     | 
    
         
            +
              require_relative "dispatchers/prepare_default"
         
     | 
| 
      
 97 
     | 
    
         
            +
              require_relative "dispatchers/prepare_ivar"
         
     | 
| 
      
 98 
     | 
    
         
            +
              require_relative "dispatchers/prepare_optional"
         
     | 
| 
      
 99 
     | 
    
         
            +
              require_relative "dispatchers/prepare_reader"
         
     | 
| 
      
 100 
     | 
    
         
            +
              require_relative "dispatchers/prepare_source"
         
     | 
| 
      
 101 
     | 
    
         
            +
              require_relative "dispatchers/prepare_target"
         
     | 
| 
      
 102 
     | 
    
         
            +
              require_relative "dispatchers/unwrap_type"
         
     | 
| 
      
 103 
     | 
    
         
            +
              require_relative "dispatchers/wrap_type"
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
              def pipeline
         
     | 
| 
      
 106 
     | 
    
         
            +
                @pipeline ||= [
         
     | 
| 
      
 107 
     | 
    
         
            +
                  PrepareSource, PrepareTarget, PrepareIvar, PrepareReader,
         
     | 
| 
      
 108 
     | 
    
         
            +
                  PrepareDefault, PrepareOptional,
         
     | 
| 
      
 109 
     | 
    
         
            +
                  UnwrapType, CheckType, BuildNestedType, WrapType
         
     | 
| 
      
 110 
     | 
    
         
            +
                ]
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Prepare nested data type from a block
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # @example
         
     | 
| 
      
 5 
     | 
    
         
            +
            #   option :foo do
         
     | 
| 
      
 6 
     | 
    
         
            +
            #     option :bar
         
     | 
| 
      
 7 
     | 
    
         
            +
            #     option :qux
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::BuildNestedType
         
     | 
| 
      
 11 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              # rubocop: disable Metrics/ParameterLists
         
     | 
| 
      
 14 
     | 
    
         
            +
              def call(parent:, source:, target:, type: nil, block: nil, **options)
         
     | 
| 
      
 15 
     | 
    
         
            +
                check_certainty!(source, type, block)
         
     | 
| 
      
 16 
     | 
    
         
            +
                check_name!(target, block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                type ||= build_nested_type(parent, target, block)
         
     | 
| 
      
 18 
     | 
    
         
            +
                { parent: parent, source: source, target: target, type: type, **options }
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              # rubocop: enable Metrics/ParameterLists
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              private
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def check_certainty!(source, type, block)
         
     | 
| 
      
 25 
     | 
    
         
            +
                return unless block
         
     | 
| 
      
 26 
     | 
    
         
            +
                return unless type
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                raise ArgumentError, <<~MESSAGE
         
     | 
| 
      
 29 
     | 
    
         
            +
                  You should define coercer of values of argument '#{source}'
         
     | 
| 
      
 30 
     | 
    
         
            +
                  either though the parameter/option, or via nested block, but not the both.
         
     | 
| 
      
 31 
     | 
    
         
            +
                MESSAGE
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def check_name!(name, block)
         
     | 
| 
      
 35 
     | 
    
         
            +
                return unless block
         
     | 
| 
      
 36 
     | 
    
         
            +
                return unless name[/^_|__|_$/]
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                raise ArgumentError, <<~MESSAGE
         
     | 
| 
      
 39 
     | 
    
         
            +
                  The name of the argument '#{name}' cannot be used for nested struct.
         
     | 
| 
      
 40 
     | 
    
         
            +
                  A proper name can use underscores _ to divide alphanumeric parts only.
         
     | 
| 
      
 41 
     | 
    
         
            +
                MESSAGE
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              def build_nested_type(parent, name, block)
         
     | 
| 
      
 45 
     | 
    
         
            +
                return unless block
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                klass_name = full_name(parent, name)
         
     | 
| 
      
 48 
     | 
    
         
            +
                build_struct(klass_name, block)
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              def full_name(parent, name)
         
     | 
| 
      
 52 
     | 
    
         
            +
                "::#{parent.name}::#{name.to_s.split("_").compact.map(&:capitalize).join}"
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              def build_struct(klass_name, block)
         
     | 
| 
      
 56 
     | 
    
         
            +
                eval "class #{klass_name} < Dry::Initializer::Struct; end"
         
     | 
| 
      
 57 
     | 
    
         
            +
                const_get(klass_name).tap { |klass| klass.class_eval(&block) }
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Checks whether an unwrapped type is valid
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::CheckType
         
     | 
| 
      
 5 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def call(source:, type: nil, wrap: 0, **options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                check_if_callable! source, type
         
     | 
| 
      
 9 
     | 
    
         
            +
                check_arity! source, type, wrap
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                { source: source, type: type, wrap: wrap, **options }
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              private
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              def check_if_callable!(source, type)
         
     | 
| 
      
 17 
     | 
    
         
            +
                return if type.nil?
         
     | 
| 
      
 18 
     | 
    
         
            +
                return if type.respond_to?(:call)
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                raise ArgumentError,
         
     | 
| 
      
 21 
     | 
    
         
            +
                      "The type of the argument '#{source}' should be callable"
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def check_arity!(_source, type, wrap)
         
     | 
| 
      
 25 
     | 
    
         
            +
                return if type.nil?
         
     | 
| 
      
 26 
     | 
    
         
            +
                return if wrap.zero?
         
     | 
| 
      
 27 
     | 
    
         
            +
                return if type.method(:call).arity.abs == 1
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                raise ArgumentError, <<~MESSAGE
         
     | 
| 
      
 30 
     | 
    
         
            +
                  The dry_intitializer supports wrapped types with one argument only.
         
     | 
| 
      
 31 
     | 
    
         
            +
                  You cannot use array types with element coercers having several arguments.
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  For example, this definitions are correct:
         
     | 
| 
      
 34 
     | 
    
         
            +
                    option :foo, [proc(&:to_s)]
         
     | 
| 
      
 35 
     | 
    
         
            +
                    option :bar, type: [[]]
         
     | 
| 
      
 36 
     | 
    
         
            +
                    option :baz, ->(a, b) { [a, b] }
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  While this is not:
         
     | 
| 
      
 39 
     | 
    
         
            +
                    option :foo, [->(a, b) { [a, b] }]
         
     | 
| 
      
 40 
     | 
    
         
            +
                MESSAGE
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
              # rubocop: enable Metrics/MethodLength
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Prepares the `:default` option
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # It must respond to `.call` without arguments
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::PrepareDefault
         
     | 
| 
      
 7 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              def call(default: nil, optional: nil, **options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                default = callable! default
         
     | 
| 
      
 11 
     | 
    
         
            +
                check_arity! default
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                { default: default, optional: (optional | default), **options }
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              private
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def callable!(default)
         
     | 
| 
      
 19 
     | 
    
         
            +
                return unless default
         
     | 
| 
      
 20 
     | 
    
         
            +
                return default if default.respond_to?(:call)
         
     | 
| 
      
 21 
     | 
    
         
            +
                return callable(default.to_proc) if default.respond_to?(:to_proc)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                invalid!(default)
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def check_arity!(default)
         
     | 
| 
      
 27 
     | 
    
         
            +
                return unless default
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                arity = default.method(:call).arity.to_i
         
     | 
| 
      
 30 
     | 
    
         
            +
                return unless arity.positive?
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                invalid!(default)
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              def invalid!(default)
         
     | 
| 
      
 36 
     | 
    
         
            +
                raise TypeError, "The #{default.inspect} should be" \
         
     | 
| 
      
 37 
     | 
    
         
            +
                                 " either convertable to proc with no arguments," \
         
     | 
| 
      
 38 
     | 
    
         
            +
                                 " or respond to #call without arguments."
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Prepares the variable name of a parameter or an option.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::PrepareIvar
         
     | 
| 
      
 5 
     | 
    
         
            +
              module_function
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def call(target:, **options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                ivar = "@#{target}".delete("?").to_sym
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                { target: target, ivar: ivar, **options }
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Defines whether an argument is optional
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::PrepareOptional
         
     | 
| 
      
 5 
     | 
    
         
            +
              module_function
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def call(optional: nil, default: nil, required: nil, **options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                optional ||= default
         
     | 
| 
      
 9 
     | 
    
         
            +
                optional &&= !required
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                { optional: !!optional, default: default, **options }
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Checks the reader privacy
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::PrepareReader
         
     | 
| 
      
 5 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def call(target: nil, reader: :public, **options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                reader = case reader.to_s
         
     | 
| 
      
 9 
     | 
    
         
            +
                         when "false", ""                      then nil
         
     | 
| 
      
 10 
     | 
    
         
            +
                         when "true"                           then :public
         
     | 
| 
      
 11 
     | 
    
         
            +
                         when "public", "private", "protected" then reader.to_sym
         
     | 
| 
      
 12 
     | 
    
         
            +
                         else invalid_reader!(target, reader)
         
     | 
| 
      
 13 
     | 
    
         
            +
                         end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                { target: target, reader: reader, **options }
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              private
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def invalid_reader!(target, _reader)
         
     | 
| 
      
 21 
     | 
    
         
            +
                raise ArgumentError, <<~MESSAGE
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Invalid setting for the ##{target} reader's privacy.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  Use the one of the following values for the `:reader` option:
         
     | 
| 
      
 24 
     | 
    
         
            +
                  - 'public' (true) for the public reader (default)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - 'private' for the private reader
         
     | 
| 
      
 26 
     | 
    
         
            +
                  - 'protected' for the protected reader
         
     | 
| 
      
 27 
     | 
    
         
            +
                  - nil (false) if no reader should be defined
         
     | 
| 
      
 28 
     | 
    
         
            +
                MESSAGE
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # The dispatcher verifies a correctness of the source name
         
     | 
| 
      
 3 
     | 
    
         
            +
            # of param or option, taken as a `:source` option.
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # We allow any stringified name for the source.
         
     | 
| 
      
 6 
     | 
    
         
            +
            # For example, this syntax is correct because we accept any key
         
     | 
| 
      
 7 
     | 
    
         
            +
            # in the original hash of arguments, but give them proper names:
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            # ```ruby
         
     | 
| 
      
 10 
     | 
    
         
            +
            # class Foo
         
     | 
| 
      
 11 
     | 
    
         
            +
            #   extend Dry::Initializer
         
     | 
| 
      
 12 
     | 
    
         
            +
            #
         
     | 
| 
      
 13 
     | 
    
         
            +
            #   option "", as: :first
         
     | 
| 
      
 14 
     | 
    
         
            +
            #   option 1,  as: :second
         
     | 
| 
      
 15 
     | 
    
         
            +
            # end
         
     | 
| 
      
 16 
     | 
    
         
            +
            #
         
     | 
| 
      
 17 
     | 
    
         
            +
            # foo = Foo.new("": 42, 1: 666)
         
     | 
| 
      
 18 
     | 
    
         
            +
            # foo.first  # => 42
         
     | 
| 
      
 19 
     | 
    
         
            +
            # foo.second # => 666
         
     | 
| 
      
 20 
     | 
    
         
            +
            # ```
         
     | 
| 
      
 21 
     | 
    
         
            +
            #
         
     | 
| 
      
 22 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::PrepareSource
         
     | 
| 
      
 23 
     | 
    
         
            +
              module_function
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              def call(source:, **options)
         
     | 
| 
      
 26 
     | 
    
         
            +
                { source: source.to_s.to_sym, **options }
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Prepares the target name of a parameter or an option.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Unlike source, the target must satisfy requirements for Ruby variable names.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # It also shouldn't be in conflict with names used by the gem.
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            module Dry::Initializer::Dispatchers::PrepareTarget
         
     | 
| 
      
 8 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              # List of variable names reserved by the gem
         
     | 
| 
      
 11 
     | 
    
         
            +
              RESERVED = %i[
         
     | 
| 
      
 12 
     | 
    
         
            +
                __dry_initializer_options__
         
     | 
| 
      
 13 
     | 
    
         
            +
                __dry_initializer_config__
         
     | 
| 
      
 14 
     | 
    
         
            +
                __dry_initializer_value__
         
     | 
| 
      
 15 
     | 
    
         
            +
                __dry_initializer_definition__
         
     | 
| 
      
 16 
     | 
    
         
            +
                __dry_initializer_initializer__
         
     | 
| 
      
 17 
     | 
    
         
            +
              ].freeze
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def call(source:, target: nil, as: nil, **options)
         
     | 
| 
      
 20 
     | 
    
         
            +
                target ||= as || source
         
     | 
| 
      
 21 
     | 
    
         
            +
                target = target.to_s.to_sym.downcase
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                check_ruby_name!(target)
         
     | 
| 
      
 24 
     | 
    
         
            +
                check_reserved_names!(target)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                { source: source, target: target, **options }
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              private
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              def check_ruby_name!(target)
         
     | 
| 
      
 32 
     | 
    
         
            +
                return if target[/\A[[:alpha:]_][[:alnum:]_]*\??\z/u]
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                raise ArgumentError,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      "The name `#{target}` is not allowed for Ruby methods"
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def check_reserved_names!(target)
         
     | 
| 
      
 39 
     | 
    
         
            +
                return unless RESERVED.include?(target)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                raise ArgumentError,
         
     | 
| 
      
 42 
     | 
    
         
            +
                      "The method name `#{target}` is reserved by the dry-initializer gem"
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     |