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,22 @@
|
|
1
|
+
#
|
2
|
+
# Looks at the `:type` option and counts how many nested arrays
|
3
|
+
# it contains around either nil or a callable value.
|
4
|
+
#
|
5
|
+
# The counted number is preserved in the `:wrap` virtual option
|
6
|
+
# used by the [WrapType] dispatcher.
|
7
|
+
#
|
8
|
+
module Dry::Initializer::Dispatchers::UnwrapType
|
9
|
+
extend self
|
10
|
+
|
11
|
+
def call(type: nil, wrap: 0, **options)
|
12
|
+
type, wrap = unwrap(type, 0)
|
13
|
+
|
14
|
+
{ type: type, wrap: wrap, **options }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def unwrap(type, count)
|
20
|
+
type.is_a?(Array) ? unwrap(type.first, count + 1) : [type, count]
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#
|
2
|
+
# Takes `:type` and `:wrap` to construct the final value coercer
|
3
|
+
#
|
4
|
+
module Dry::Initializer::Dispatchers::WrapType
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def call(type: nil, wrap: 0, **options)
|
8
|
+
{ type: wrapped_type(type, wrap), **options }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def wrapped_type(type, count)
|
14
|
+
return type if count.zero?
|
15
|
+
|
16
|
+
->(value) { wrap_value(value, count, type) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def wrap_value(value, count, type)
|
20
|
+
if count.zero?
|
21
|
+
type ? type.call(value) : value
|
22
|
+
else
|
23
|
+
return [wrap_value(value, count - 1, type)] unless value.is_a?(Array)
|
24
|
+
value.map { |item| wrap_value(item, count - 1, type) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Dry::Initializer
|
2
|
+
# Module-level DSL
|
3
|
+
module DSL
|
4
|
+
# Setting for null (undefined value)
|
5
|
+
# @return [nil, Dry::Initializer::UNDEFINED]
|
6
|
+
attr_reader :null
|
7
|
+
|
8
|
+
# Returns a version of the module with custom settings
|
9
|
+
# @option settings [Boolean] :undefined
|
10
|
+
# If unassigned params and options should be treated different from nil
|
11
|
+
# @return [Dry::Initializer]
|
12
|
+
def [](undefined: true, **)
|
13
|
+
null = (undefined == false) ? nil : UNDEFINED
|
14
|
+
Module.new.tap do |mod|
|
15
|
+
mod.extend DSL
|
16
|
+
mod.include self
|
17
|
+
mod.send(:instance_variable_set, :@null, null)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns mixin module to be included to target class by hand
|
22
|
+
# @return [Module]
|
23
|
+
# @yield proc defining params and options
|
24
|
+
def define(procedure = nil, &block)
|
25
|
+
config = Config.new(null: null)
|
26
|
+
config.instance_exec(&(procedure || block))
|
27
|
+
config.mixin.include Mixin::Root
|
28
|
+
config.mixin
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def extended(klass)
|
34
|
+
config = Config.new(klass, null: null)
|
35
|
+
klass.send :instance_variable_set, :@dry_initializer, config
|
36
|
+
klass.include Mixin::Root
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.extended(mod)
|
40
|
+
mod.instance_variable_set :@null, UNDEFINED
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dry::Initializer
|
2
|
+
# @private
|
3
|
+
module Mixin
|
4
|
+
extend DSL # @deprecated
|
5
|
+
include Dry::Initializer # @deprecated
|
6
|
+
def self.extended(klass) # @deprecated
|
7
|
+
warn "[DEPRECATED] Use Dry::Initializer instead of its alias" \
|
8
|
+
" Dry::Initializer::Mixin. The later will be removed in v2.1.0"
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
require_relative "mixin/root"
|
13
|
+
require_relative "mixin/local"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Dry::Initializer::Mixin
|
2
|
+
# @private
|
3
|
+
module Local
|
4
|
+
attr_reader :klass
|
5
|
+
|
6
|
+
def inspect
|
7
|
+
"Dry::Initializer::Mixin::Local[#{klass}]"
|
8
|
+
end
|
9
|
+
alias to_s inspect
|
10
|
+
alias to_str inspect
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def included(klass)
|
15
|
+
@klass = klass
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#
|
2
|
+
# The nested structure that takes nested hashes with indifferent access
|
3
|
+
#
|
4
|
+
class Dry::Initializer::Struct
|
5
|
+
extend Dry::Initializer
|
6
|
+
|
7
|
+
class << self
|
8
|
+
undef_method :param
|
9
|
+
|
10
|
+
def new(options)
|
11
|
+
super(**Hash(options).each_with_object({}) { |(k, v), h| h[k.to_sym] = v })
|
12
|
+
end
|
13
|
+
alias call new
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Represents event data as a nested hash with deeply stringified keys
|
18
|
+
# @return [Hash<String, ...>]
|
19
|
+
#
|
20
|
+
def to_h
|
21
|
+
self
|
22
|
+
.class
|
23
|
+
.dry_initializer
|
24
|
+
.attributes(self)
|
25
|
+
.each_with_object({}) { |(k, v), h| h[k.to_s] = __hashify(v) }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def __hashify(value)
|
31
|
+
case value
|
32
|
+
when Hash
|
33
|
+
value.each_with_object({}) { |(k, v), obj| obj[k.to_s] = __hashify(v) }
|
34
|
+
when Array then value.map { |v| __hashify(v) }
|
35
|
+
when Dry::Initializer::Struct then value.to_h
|
36
|
+
else value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
namespace :benchmark do
|
2
|
+
desc "Runs benchmarks for plain params"
|
3
|
+
task :plain_params do
|
4
|
+
system "ruby benchmarks/plain_params.rb"
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "Runs benchmarks for plain options"
|
8
|
+
task :plain_options do
|
9
|
+
system "ruby benchmarks/plain_options.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Runs benchmarks for value coercion"
|
13
|
+
task :with_coercion do
|
14
|
+
system "ruby benchmarks/with_coercion.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Runs benchmarks with defaults"
|
18
|
+
task :with_defaults do
|
19
|
+
system "ruby benchmarks/with_defaults.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Runs benchmarks with defaults and coercion"
|
23
|
+
task :with_defaults_and_coercion do
|
24
|
+
system "ruby benchmarks/with_defaults_and_coercion.rb"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Runs benchmarks for several defaults"
|
28
|
+
task :compare_several_defaults do
|
29
|
+
system "ruby benchmarks/with_several_defaults.rb"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Runs all benchmarks"
|
34
|
+
task benchmark: %i[
|
35
|
+
benchmark:plain_params
|
36
|
+
benchmark:plain_options
|
37
|
+
benchmark:with_coercion
|
38
|
+
benchmark:with_defaults
|
39
|
+
benchmark:with_defaults_and_coercion
|
40
|
+
benchmark:compare_several_defaults
|
41
|
+
]
|
@@ -0,0 +1,78 @@
|
|
1
|
+
namespace :profile do
|
2
|
+
def profile(name, execution, &definition)
|
3
|
+
require "dry-initializer"
|
4
|
+
require "ruby-prof"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
definition.call
|
8
|
+
result = RubyProf.profile do
|
9
|
+
1_000.times { execution.call }
|
10
|
+
end
|
11
|
+
|
12
|
+
FileUtils.mkdir_p "./tmp"
|
13
|
+
|
14
|
+
FileUtils.touch "./tmp/#{name}.dot"
|
15
|
+
File.open("./tmp/#{name}.dot", "w+") do |output|
|
16
|
+
RubyProf::DotPrinter.new(result).print(output, min_percent: 0)
|
17
|
+
end
|
18
|
+
|
19
|
+
FileUtils.touch "./tmp/#{name}.html"
|
20
|
+
File.open("./tmp/#{name}.html", "w+") do |output|
|
21
|
+
RubyProf::CallStackPrinter.new(result).print(output, min_percent: 0)
|
22
|
+
end
|
23
|
+
|
24
|
+
system "dot -Tpng ./tmp/#{name}.dot > ./tmp/#{name}.png"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Profiles initialization with required param and option"
|
28
|
+
task :required do
|
29
|
+
profile("required", -> { User.new :Andy, email: "andy@example.com" }) do
|
30
|
+
class User
|
31
|
+
extend Dry::Initializer
|
32
|
+
param :name
|
33
|
+
option :email
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Profiles initialization with default param and option"
|
39
|
+
task :defaults do
|
40
|
+
profile("defaults", -> { User.new }) do
|
41
|
+
class User
|
42
|
+
extend Dry::Initializer
|
43
|
+
param :name, default: -> { :Andy }
|
44
|
+
option :email, default: -> { "andy@example.com" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Profiles initialization with coerced param and option"
|
50
|
+
task :coercion do
|
51
|
+
profile("coercion", -> { User.new :Andy, email: :"andy@example.com" }) do
|
52
|
+
class User
|
53
|
+
extend Dry::Initializer
|
54
|
+
param :name, proc(&:to_s)
|
55
|
+
option :email, proc(&:to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Profiles initialization with coerced defaults of param and option"
|
61
|
+
task :default_coercion do
|
62
|
+
profile("default_coercion", -> { User.new }) do
|
63
|
+
class User
|
64
|
+
extend Dry::Initializer
|
65
|
+
param :name, proc(&:to_s), default: -> { :Andy }
|
66
|
+
option :email, proc(&:to_s), default: -> { :"andy@example.com" }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "Makes all profiling at once"
|
73
|
+
task profile: %i[
|
74
|
+
profile:required
|
75
|
+
profile:defaults
|
76
|
+
profile:coercion
|
77
|
+
profile:default_coercion
|
78
|
+
]
|
@@ -0,0 +1,38 @@
|
|
1
|
+
describe Dry::Initializer, "dry_initializer.attributes" do
|
2
|
+
subject { instance.class.dry_initializer.attributes(instance) }
|
3
|
+
|
4
|
+
context "when class has params" do
|
5
|
+
before do
|
6
|
+
class Test::Foo
|
7
|
+
extend Dry::Initializer
|
8
|
+
param :foo, proc(&:to_s)
|
9
|
+
param :bar, default: proc { 1 }
|
10
|
+
param :baz, optional: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:instance) { Test::Foo.new(:FOO) }
|
15
|
+
|
16
|
+
it "collects coerced params with default values" do
|
17
|
+
expect(subject).to eq({ foo: "FOO", bar: 1 })
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when class has options" do
|
22
|
+
before do
|
23
|
+
class Test::Foo
|
24
|
+
extend Dry::Initializer
|
25
|
+
option :foo
|
26
|
+
option :bar, default: proc { 1 }
|
27
|
+
option :baz, optional: true
|
28
|
+
option :qux, proc(&:to_s), as: :quxx
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:instance) { Test::Foo.new(foo: :FOO, qux: :QUX) }
|
33
|
+
|
34
|
+
it "collects coerced and renamed options with default values" do
|
35
|
+
expect(subject).to eq({ foo: :FOO, bar: 1, quxx: "QUX" })
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
describe "coercion of nil" do
|
2
|
+
before do
|
3
|
+
class Test::Foo
|
4
|
+
extend Dry::Initializer
|
5
|
+
param :bar, proc(&:to_i)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Test::Baz
|
9
|
+
include Dry::Initializer.define -> do
|
10
|
+
param :qux, proc(&:to_i)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:foo) { Test::Foo.new(nil) }
|
16
|
+
let(:baz) { Test::Baz.new(nil) }
|
17
|
+
|
18
|
+
it "works with extend syntax" do
|
19
|
+
expect(foo.bar).to eq 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it "works with include syntax" do
|
23
|
+
expect(baz.qux).to eq 0
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
describe "custom dispatchers" do
|
2
|
+
subject { Test::Foo.new "123" }
|
3
|
+
|
4
|
+
before do
|
5
|
+
dispatcher = ->(op) { op[:integer] ? op.merge(type: proc(&:to_i)) : op }
|
6
|
+
Dry::Initializer::Dispatchers << dispatcher
|
7
|
+
end
|
8
|
+
|
9
|
+
context "with extend syntax" do
|
10
|
+
before do
|
11
|
+
class Test::Foo
|
12
|
+
extend Dry::Initializer
|
13
|
+
param :id, integer: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "adds syntax sugar" do
|
18
|
+
expect(subject.id).to eq 123
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with include syntax" do
|
23
|
+
before do
|
24
|
+
class Test::Foo
|
25
|
+
include Dry::Initializer.define -> do
|
26
|
+
param :id, integer: true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "adds syntax sugar" do
|
32
|
+
expect(subject.id).to eq 123
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
describe "custom initializer" do
|
2
|
+
before do
|
3
|
+
class Test::Foo
|
4
|
+
extend Dry::Initializer
|
5
|
+
|
6
|
+
param :bar
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
@bar *= 3
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Test::Baz < Test::Foo
|
15
|
+
param :qux
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
super
|
19
|
+
@qux += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "reloads the initializer" do
|
25
|
+
baz = Test::Baz.new(5, 5)
|
26
|
+
|
27
|
+
expect(baz.bar).to eq 15 # 5 * 3
|
28
|
+
expect(baz.qux).to eq 6 # 5 + 1
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
describe "default values" do
|
2
|
+
before do
|
3
|
+
class Test::Foo
|
4
|
+
extend Dry::Initializer
|
5
|
+
|
6
|
+
param :foo, default: proc { :FOO }
|
7
|
+
param :bar, default: proc { :BAR }
|
8
|
+
option :baz, default: -> { :BAZ }
|
9
|
+
option :qux, default: proc { foo }
|
10
|
+
option :mox, default: -> { default_mox }
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def default_mox
|
15
|
+
:MOX
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "instantiate arguments" do
|
21
|
+
subject = Test::Foo.new(1, 2, baz: 3, qux: 4)
|
22
|
+
|
23
|
+
expect(subject.foo).to eql 1
|
24
|
+
expect(subject.bar).to eql 2
|
25
|
+
expect(subject.baz).to eql 3
|
26
|
+
expect(subject.qux).to eql 4
|
27
|
+
end
|
28
|
+
|
29
|
+
it "applies default values" do
|
30
|
+
subject = Test::Foo.new
|
31
|
+
|
32
|
+
expect(subject.foo).to eql :FOO
|
33
|
+
expect(subject.bar).to eql :BAR
|
34
|
+
expect(subject.baz).to eql :BAZ
|
35
|
+
expect(subject.qux).to eql :FOO
|
36
|
+
end
|
37
|
+
|
38
|
+
it "applies default values partially" do
|
39
|
+
subject = Test::Foo.new 1, baz: 3
|
40
|
+
|
41
|
+
expect(subject.foo).to eql 1
|
42
|
+
expect(subject.bar).to eql :BAR
|
43
|
+
expect(subject.baz).to eql 3
|
44
|
+
expect(subject.qux).to eql 1
|
45
|
+
end
|
46
|
+
|
47
|
+
it "applies default values from private methods" do
|
48
|
+
subject = Test::Foo.new
|
49
|
+
expect(subject.mox).to eql :MOX
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "when the last param has a default and there are no options" do
|
53
|
+
before do
|
54
|
+
class Test::Bar
|
55
|
+
extend Dry::Initializer
|
56
|
+
|
57
|
+
param :foo
|
58
|
+
param :bar, default: proc { {} }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "instantiates arguments" do
|
63
|
+
subject = Test::Bar.new(1, 2)
|
64
|
+
|
65
|
+
expect(subject.foo).to eql 1
|
66
|
+
expect(subject.bar).to eql 2
|
67
|
+
end
|
68
|
+
|
69
|
+
it "applies default values" do
|
70
|
+
subject = Test::Bar.new(1)
|
71
|
+
|
72
|
+
expect(subject.foo).to eql 1
|
73
|
+
expect(subject.bar).to eql({})
|
74
|
+
end
|
75
|
+
|
76
|
+
it "instantiates arguments also if the last is an hash" do
|
77
|
+
subject = Test::Bar.new(1, { baz: 2, qux: 3 })
|
78
|
+
|
79
|
+
expect(subject.foo).to eql 1
|
80
|
+
expect(subject.bar).to eql({ baz: 2, qux: 3 })
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|