dry-initializer 3.0.1
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 +23 -0
- data/.gitignore +10 -0
- data/.rspec +4 -0
- data/.rubocop.yml +51 -0
- data/.travis.yml +28 -0
- data/CHANGELOG.md +883 -0
- data/Gemfile +29 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -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/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 +10 -0
- data/lib/dry/initializer/struct.rb +40 -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 +44 -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 +22 -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 +189 -0
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            Bundler.require(:benchmarks)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "dry-initializer"
         | 
| 4 | 
            +
            class DryTest
         | 
| 5 | 
            +
              extend Dry::Initializer[undefined: false]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              option :foo, default: -> { "FOO" }
         | 
| 8 | 
            +
              option :bar, default: -> { "BAR" }
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class DryTestUndefined
         | 
| 12 | 
            +
              extend Dry::Initializer
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              option :foo, default: -> { "FOO" }
         | 
| 15 | 
            +
              option :bar, default: -> { "BAR" }
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            class PlainRubyTest
         | 
| 19 | 
            +
              attr_reader :foo, :bar
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def initialize(foo: "FOO", bar: "BAR")
         | 
| 22 | 
            +
                @foo = foo
         | 
| 23 | 
            +
                @bar = bar
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            require "kwattr"
         | 
| 28 | 
            +
            class KwattrTest
         | 
| 29 | 
            +
              kwattr foo: "FOO", bar: "BAR"
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            require "active_attr"
         | 
| 33 | 
            +
            class ActiveAttrTest
         | 
| 34 | 
            +
              include ActiveAttr::AttributeDefaults
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              attribute :foo, default: "FOO"
         | 
| 37 | 
            +
              attribute :bar, default: "BAR"
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            puts "Benchmark for instantiation with default values"
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            Benchmark.ips do |x|
         | 
| 43 | 
            +
              x.config time: 15, warmup: 10
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              x.report("plain Ruby") do
         | 
| 46 | 
            +
                PlainRubyTest.new
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              x.report("dry-initializer") do
         | 
| 50 | 
            +
                DryTest.new
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              x.report("dry-initializer (with UNDEFINED)") do
         | 
| 54 | 
            +
                DryTestUndefined.new
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              x.report("kwattr") do
         | 
| 58 | 
            +
                KwattrTest.new
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
              x.report("active_attr") do
         | 
| 62 | 
            +
                ActiveAttrTest.new
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              x.compare!
         | 
| 66 | 
            +
            end
         | 
| @@ -0,0 +1,59 @@ | |
| 1 | 
            +
            Bundler.require(:benchmarks)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "dry-initializer"
         | 
| 4 | 
            +
            class DryTest
         | 
| 5 | 
            +
              extend Dry::Initializer[undefined: false]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              option :foo, proc(&:to_s), default: -> { "FOO" }
         | 
| 8 | 
            +
              option :bar, proc(&:to_s), default: -> { "BAR" }
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class DryTestUndefined
         | 
| 12 | 
            +
              extend Dry::Initializer
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              option :foo, proc(&:to_s), default: -> { "FOO" }
         | 
| 15 | 
            +
              option :bar, proc(&:to_s), default: -> { "BAR" }
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            class PlainRubyTest
         | 
| 19 | 
            +
              attr_reader :foo, :bar
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def initialize(foo: "FOO", bar: "BAR")
         | 
| 22 | 
            +
                @foo = foo
         | 
| 23 | 
            +
                @bar = bar
         | 
| 24 | 
            +
                raise TypeError unless String === @foo
         | 
| 25 | 
            +
                raise TypeError unless String === @bar
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            require "virtus"
         | 
| 30 | 
            +
            class VirtusTest
         | 
| 31 | 
            +
              include Virtus.model
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              attribute :foo, String, default: "FOO"
         | 
| 34 | 
            +
              attribute :bar, String, default: "BAR"
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            puts "Benchmark for instantiation with type constraints and default values"
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            Benchmark.ips do |x|
         | 
| 40 | 
            +
              x.config time: 15, warmup: 10
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              x.report("plain Ruby") do
         | 
| 43 | 
            +
                PlainRubyTest.new
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              x.report("dry-initializer") do
         | 
| 47 | 
            +
                DryTest.new
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              x.report("dry-initializer (with UNDEFINED)") do
         | 
| 51 | 
            +
                DryTest.new
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              x.report("virtus") do
         | 
| 55 | 
            +
                VirtusTest.new
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              x.compare!
         | 
| 59 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Gem::Specification.new do |gem|
         | 
| 2 | 
            +
              gem.name     = "dry-initializer"
         | 
| 3 | 
            +
              gem.version  = "3.0.1"
         | 
| 4 | 
            +
              gem.author   = ["Vladimir Kochnev (marshall-lee)", "Andrew Kozin (nepalez)"]
         | 
| 5 | 
            +
              gem.email    = "andrew.kozin@gmail.com"
         | 
| 6 | 
            +
              gem.homepage = "https://github.com/dry-rb/dry-initializer"
         | 
| 7 | 
            +
              gem.summary  = "DSL for declaring params and options of the initializer"
         | 
| 8 | 
            +
              gem.license  = "MIT"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              gem.files            = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
         | 
| 11 | 
            +
              gem.test_files       = gem.files.grep(/^spec/)
         | 
| 12 | 
            +
              gem.extra_rdoc_files = Dir["README.md", "LICENSE", "CHANGELOG.md"]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              gem.required_ruby_version = ">= 2.3"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              gem.add_development_dependency "rspec", "~> 3.0"
         | 
| 17 | 
            +
              gem.add_development_dependency "rake", "> 10"
         | 
| 18 | 
            +
              gem.add_development_dependency "dry-types", "> 0.5.1"
         | 
| 19 | 
            +
              gem.add_development_dependency "rubocop", "~> 0.49.0"
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            require_relative "dry/initializer"
         | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            require "set"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Namespace for gems in a dry-rb community
         | 
| 4 | 
            +
            module Dry
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              # DSL for declaring params and options of class initializers
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              module Initializer
         | 
| 9 | 
            +
                require_relative "initializer/undefined"
         | 
| 10 | 
            +
                require_relative "initializer/dsl"
         | 
| 11 | 
            +
                require_relative "initializer/definition"
         | 
| 12 | 
            +
                require_relative "initializer/builders"
         | 
| 13 | 
            +
                require_relative "initializer/config"
         | 
| 14 | 
            +
                require_relative "initializer/mixin"
         | 
| 15 | 
            +
                require_relative "initializer/dispatchers"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                # Adds methods [.[]] and [.define]
         | 
| 18 | 
            +
                extend DSL
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                # Gem-related configuration
         | 
| 21 | 
            +
                # @return [Dry::Initializer::Config]
         | 
| 22 | 
            +
                def dry_initializer
         | 
| 23 | 
            +
                  @dry_initializer ||= Config.new(self)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # Adds or redefines a parameter of [#dry_initializer]
         | 
| 27 | 
            +
                # @param  [Symbol]       name
         | 
| 28 | 
            +
                # @param  [#call, nil]   type (nil)
         | 
| 29 | 
            +
                # @option opts [Proc]    :default
         | 
| 30 | 
            +
                # @option opts [Boolean] :optional
         | 
| 31 | 
            +
                # @option opts [Symbol]  :as
         | 
| 32 | 
            +
                # @option opts [true, false, :protected, :public, :private] :reader
         | 
| 33 | 
            +
                # @yield block with nested definition
         | 
| 34 | 
            +
                # @return [self] itself
         | 
| 35 | 
            +
                def param(name, type = nil, **opts, &block)
         | 
| 36 | 
            +
                  dry_initializer.param(name, type, **opts, &block)
         | 
| 37 | 
            +
                  self
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                # Adds or redefines an option of [#dry_initializer]
         | 
| 41 | 
            +
                # @param  (see #param)
         | 
| 42 | 
            +
                # @option (see #param)
         | 
| 43 | 
            +
                # @yield  (see #param)
         | 
| 44 | 
            +
                # @return (see #param)
         | 
| 45 | 
            +
                def option(name, type = nil, **opts, &block)
         | 
| 46 | 
            +
                  dry_initializer.option(name, type, **opts, &block)
         | 
| 47 | 
            +
                  self
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                private
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def inherited(klass)
         | 
| 53 | 
            +
                  super
         | 
| 54 | 
            +
                  config = Config.new(klass, null: dry_initializer.null)
         | 
| 55 | 
            +
                  klass.send(:instance_variable_set, :@dry_initializer, config)
         | 
| 56 | 
            +
                  dry_initializer.children << config
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                require_relative "initializer/struct"
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            module Dry::Initializer::Builders
         | 
| 2 | 
            +
              # @private
         | 
| 3 | 
            +
              class Attribute
         | 
| 4 | 
            +
                def self.[](definition)
         | 
| 5 | 
            +
                  new(definition).call
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def call
         | 
| 9 | 
            +
                  lines.compact
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                private
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # rubocop: disable Metrics/MethodLength
         | 
| 15 | 
            +
                def initialize(definition)
         | 
| 16 | 
            +
                  @definition = definition
         | 
| 17 | 
            +
                  @option     = definition.option
         | 
| 18 | 
            +
                  @type       = definition.type
         | 
| 19 | 
            +
                  @optional   = definition.optional
         | 
| 20 | 
            +
                  @default    = definition.default
         | 
| 21 | 
            +
                  @source     = definition.source
         | 
| 22 | 
            +
                  @ivar       = definition.ivar
         | 
| 23 | 
            +
                  @null       = definition.null ? "Dry::Initializer::UNDEFINED" : "nil"
         | 
| 24 | 
            +
                  @opts       = "__dry_initializer_options__"
         | 
| 25 | 
            +
                  @congif     = "__dry_initializer_config__"
         | 
| 26 | 
            +
                  @item       = "__dry_initializer_definition__"
         | 
| 27 | 
            +
                  @val        = @option ? "__dry_initializer_value__" : @source
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                # rubocop: enable Metrics/MethodLength
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def lines
         | 
| 32 | 
            +
                  [
         | 
| 33 | 
            +
                    "",
         | 
| 34 | 
            +
                    definition_line,
         | 
| 35 | 
            +
                    reader_line,
         | 
| 36 | 
            +
                    default_line,
         | 
| 37 | 
            +
                    coercion_line,
         | 
| 38 | 
            +
                    assignment_line
         | 
| 39 | 
            +
                  ]
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def reader_line
         | 
| 43 | 
            +
                  return unless @option
         | 
| 44 | 
            +
                  @optional ? optional_reader : required_reader
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def optional_reader
         | 
| 48 | 
            +
                  "#{@val} = #{@opts}.fetch(:'#{@source}', #{@null})"
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def required_reader
         | 
| 52 | 
            +
                  "#{@val} = #{@opts}.fetch(:'#{@source}')" \
         | 
| 53 | 
            +
                  " { raise KeyError, \"\#{self.class}: #{@definition} is required\" }"
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def definition_line
         | 
| 57 | 
            +
                  return unless @type || @default
         | 
| 58 | 
            +
                  "#{@item} = __dry_initializer_config__.definitions[:'#{@source}']"
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def default_line
         | 
| 62 | 
            +
                  return unless @default
         | 
| 63 | 
            +
                  "#{@val} = instance_exec(&#{@item}.default) if #{@null} == #{@val}"
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def coercion_line
         | 
| 67 | 
            +
                  return unless @type
         | 
| 68 | 
            +
                  arity = @type.is_a?(Proc) ? @type.arity : @type.method(:call).arity
         | 
| 69 | 
            +
                  if arity.abs == 1
         | 
| 70 | 
            +
                    "#{@val} = #{@item}.type.call(#{@val}) unless #{@null} == #{@val}"
         | 
| 71 | 
            +
                  else
         | 
| 72 | 
            +
                    "#{@val} = #{@item}.type.call(#{@val}, self) unless #{@null} == #{@val}"
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                def assignment_line
         | 
| 77 | 
            +
                  "#{@ivar} = #{@val}" \
         | 
| 78 | 
            +
                  " unless #{@null} == #{@val} && instance_variable_defined?(:#{@ivar})"
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
            end
         | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            module Dry::Initializer::Builders
         | 
| 2 | 
            +
              # @private
         | 
| 3 | 
            +
              class Initializer
         | 
| 4 | 
            +
                require_relative "signature"
         | 
| 5 | 
            +
                require_relative "attribute"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.[](config)
         | 
| 8 | 
            +
                  new(config).call
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def call
         | 
| 12 | 
            +
                  lines.flatten.compact.join("\n")
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize(config)
         | 
| 18 | 
            +
                  @config = config
         | 
| 19 | 
            +
                  @definitions = config.definitions.values
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def lines
         | 
| 23 | 
            +
                  [
         | 
| 24 | 
            +
                    undef_line,
         | 
| 25 | 
            +
                    define_line,
         | 
| 26 | 
            +
                    params_lines,
         | 
| 27 | 
            +
                    options_lines,
         | 
| 28 | 
            +
                    end_line
         | 
| 29 | 
            +
                  ]
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def undef_line
         | 
| 33 | 
            +
                  "undef :__dry_initializer_initialize__" \
         | 
| 34 | 
            +
                  " if private_method_defined? :__dry_initializer_initialize__"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def define_line
         | 
| 38 | 
            +
                  "private def __dry_initializer_initialize__(#{Signature[@config]})"
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def params_lines
         | 
| 42 | 
            +
                  @definitions.reject(&:option)
         | 
| 43 | 
            +
                              .flat_map { |item| Attribute[item] }
         | 
| 44 | 
            +
                              .map { |line| "  " << line }
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def options_lines
         | 
| 48 | 
            +
                  @definitions.select(&:option)
         | 
| 49 | 
            +
                              .flat_map { |item| Attribute[item] }
         | 
| 50 | 
            +
                              .map { |line| "  " << line }
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def end_line
         | 
| 54 | 
            +
                  "end"
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def private_line
         | 
| 58 | 
            +
                  "private :__dry_initializer_initialize__"
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module Dry::Initializer::Builders
         | 
| 2 | 
            +
              # @private
         | 
| 3 | 
            +
              class Reader
         | 
| 4 | 
            +
                def self.[](definition)
         | 
| 5 | 
            +
                  new(definition).call
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def call
         | 
| 9 | 
            +
                  lines.flatten.compact.join("\n")
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                private
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def initialize(definition)
         | 
| 15 | 
            +
                  @target = definition.target
         | 
| 16 | 
            +
                  @ivar   = definition.ivar
         | 
| 17 | 
            +
                  @null   = definition.null
         | 
| 18 | 
            +
                  @reader = definition.reader
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def lines
         | 
| 22 | 
            +
                  [undef_line, attribute_line, method_lines, type_line]
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def undef_line
         | 
| 26 | 
            +
                  "undef :#{@target} if method_defined?(:#{@target})" \
         | 
| 27 | 
            +
                  "  || private_method_defined?(:#{@target})" \
         | 
| 28 | 
            +
                  "  || protected_method_defined?(:#{@target})"
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def attribute_line
         | 
| 32 | 
            +
                  return unless @reader
         | 
| 33 | 
            +
                  "attr_reader :#{@target}" unless @null
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def method_lines
         | 
| 37 | 
            +
                  return unless @reader
         | 
| 38 | 
            +
                  return unless @null
         | 
| 39 | 
            +
                  [
         | 
| 40 | 
            +
                    "def #{@target}",
         | 
| 41 | 
            +
                    "  #{@ivar} unless Dry::Initializer::UNDEFINED == #{@ivar}",
         | 
| 42 | 
            +
                    "end"
         | 
| 43 | 
            +
                  ]
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def type_line
         | 
| 47 | 
            +
                  "#{@reader} :#{@target}" if %i[private protected].include? @reader
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            module Dry::Initializer::Builders
         | 
| 2 | 
            +
              # @private
         | 
| 3 | 
            +
              class Signature
         | 
| 4 | 
            +
                def self.[](config)
         | 
| 5 | 
            +
                  new(config).call
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def call
         | 
| 9 | 
            +
                  [*required_params, *optional_params, "*", options].compact.join(", ")
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                private
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def initialize(config)
         | 
| 15 | 
            +
                  @config  = config
         | 
| 16 | 
            +
                  @options = config.options.any?
         | 
| 17 | 
            +
                  @null    = config.null ? "Dry::Initializer::UNDEFINED" : "nil"
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def required_params
         | 
| 21 | 
            +
                  @config.params.reject(&:optional).map(&:source)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def optional_params
         | 
| 25 | 
            +
                  @config.params.select(&:optional).map { |rec| "#{rec.source} = #{@null}" }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def options
         | 
| 29 | 
            +
                  "**__dry_initializer_options__" if @options
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         |