dry-initializer 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/---bug-report.md +1 -5
- data/.github/workflows/custom_ci.yml +31 -47
- data/.github/workflows/sync_configs.yml +29 -7
- data/.rspec +1 -1
- data/.rubocop.yml +19 -6
- data/CHANGELOG.md +6 -0
- data/Gemfile +27 -29
- data/Gemfile.devtools +16 -0
- data/Guardfile +3 -3
- data/LICENSE +1 -1
- data/README.md +17 -77
- data/Rakefile +4 -4
- data/benchmarks/compare_several_defaults.rb +27 -27
- data/benchmarks/plain_options.rb +14 -14
- data/benchmarks/plain_params.rb +22 -22
- data/benchmarks/with_coercion.rb +14 -14
- data/benchmarks/with_defaults.rb +17 -17
- data/benchmarks/with_defaults_and_coercion.rb +14 -14
- data/bin/.gitkeep +0 -0
- data/dry-initializer.gemspec +13 -13
- data/lib/dry-initializer.rb +1 -1
- data/lib/dry/initializer.rb +9 -9
- data/lib/dry/initializer/builders.rb +2 -2
- data/lib/dry/initializer/builders/attribute.rb +12 -7
- data/lib/dry/initializer/builders/initializer.rb +9 -13
- data/lib/dry/initializer/builders/reader.rb +3 -1
- data/lib/dry/initializer/builders/signature.rb +3 -3
- data/lib/dry/initializer/config.rb +6 -4
- data/lib/dry/initializer/definition.rb +9 -9
- data/lib/dry/initializer/dispatchers.rb +10 -10
- data/lib/dry/initializer/dispatchers/prepare_default.rb +2 -2
- data/lib/dry/initializer/dispatchers/prepare_ivar.rb +1 -1
- data/lib/dry/initializer/dispatchers/prepare_reader.rb +3 -3
- data/lib/dry/initializer/dispatchers/wrap_type.rb +1 -0
- data/lib/dry/initializer/mixin.rb +4 -4
- data/lib/dry/initializer/version.rb +5 -0
- data/lib/tasks/benchmark.rake +13 -13
- data/lib/tasks/profile.rake +16 -16
- data/project.yml +2 -0
- data/spec/attributes_spec.rb +7 -7
- data/spec/coercion_of_nil_spec.rb +3 -3
- data/spec/custom_dispatchers_spec.rb +6 -6
- data/spec/custom_initializer_spec.rb +2 -2
- data/spec/default_values_spec.rb +9 -9
- data/spec/definition_spec.rb +10 -10
- data/spec/invalid_default_spec.rb +2 -2
- data/spec/list_type_spec.rb +8 -8
- data/spec/missed_default_spec.rb +2 -2
- data/spec/nested_type_spec.rb +10 -10
- data/spec/optional_spec.rb +16 -16
- data/spec/options_tolerance_spec.rb +2 -2
- data/spec/public_attributes_utility_spec.rb +5 -5
- data/spec/reader_spec.rb +13 -13
- data/spec/repetitive_definitions_spec.rb +9 -9
- data/spec/several_assignments_spec.rb +9 -9
- data/spec/spec_helper.rb +3 -8
- data/spec/subclassing_spec.rb +5 -5
- data/spec/support/coverage.rb +7 -0
- data/spec/support/warnings.rb +7 -0
- data/spec/type_argument_spec.rb +13 -13
- data/spec/type_constraint_spec.rb +44 -26
- data/spec/value_coercion_via_dry_types_spec.rb +7 -7
- metadata +11 -31
data/lib/tasks/profile.rake
CHANGED
@@ -1,32 +1,32 @@
|
|
1
1
|
namespace :profile do
|
2
2
|
def profile(name, execution, &definition)
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'dry-initializer'
|
4
|
+
require 'ruby-prof'
|
5
|
+
require 'fileutils'
|
6
6
|
|
7
7
|
definition.call
|
8
8
|
result = RubyProf.profile do
|
9
9
|
1_000.times { execution.call }
|
10
10
|
end
|
11
11
|
|
12
|
-
FileUtils.mkdir_p
|
12
|
+
FileUtils.mkdir_p './tmp'
|
13
13
|
|
14
14
|
FileUtils.touch "./tmp/#{name}.dot"
|
15
|
-
File.open("./tmp/#{name}.dot",
|
15
|
+
File.open("./tmp/#{name}.dot", 'w+') do |output|
|
16
16
|
RubyProf::DotPrinter.new(result).print(output, min_percent: 0)
|
17
17
|
end
|
18
18
|
|
19
19
|
FileUtils.touch "./tmp/#{name}.html"
|
20
|
-
File.open("./tmp/#{name}.html",
|
20
|
+
File.open("./tmp/#{name}.html", 'w+') do |output|
|
21
21
|
RubyProf::CallStackPrinter.new(result).print(output, min_percent: 0)
|
22
22
|
end
|
23
23
|
|
24
24
|
system "dot -Tpng ./tmp/#{name}.dot > ./tmp/#{name}.png"
|
25
25
|
end
|
26
26
|
|
27
|
-
desc
|
27
|
+
desc 'Profiles initialization with required param and option'
|
28
28
|
task :required do
|
29
|
-
profile(
|
29
|
+
profile('required', -> { User.new :Andy, email: 'andy@example.com' }) do
|
30
30
|
class User
|
31
31
|
extend Dry::Initializer
|
32
32
|
param :name
|
@@ -35,20 +35,20 @@ namespace :profile do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
desc
|
38
|
+
desc 'Profiles initialization with default param and option'
|
39
39
|
task :defaults do
|
40
|
-
profile(
|
40
|
+
profile('defaults', -> { User.new }) do
|
41
41
|
class User
|
42
42
|
extend Dry::Initializer
|
43
43
|
param :name, default: -> { :Andy }
|
44
|
-
option :email, default: -> {
|
44
|
+
option :email, default: -> { 'andy@example.com' }
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
desc
|
49
|
+
desc 'Profiles initialization with coerced param and option'
|
50
50
|
task :coercion do
|
51
|
-
profile(
|
51
|
+
profile('coercion', -> { User.new :Andy, email: :"andy@example.com" }) do
|
52
52
|
class User
|
53
53
|
extend Dry::Initializer
|
54
54
|
param :name, proc(&:to_s)
|
@@ -57,9 +57,9 @@ namespace :profile do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
desc
|
60
|
+
desc 'Profiles initialization with coerced defaults of param and option'
|
61
61
|
task :default_coercion do
|
62
|
-
profile(
|
62
|
+
profile('default_coercion', -> { User.new }) do
|
63
63
|
class User
|
64
64
|
extend Dry::Initializer
|
65
65
|
param :name, proc(&:to_s), default: -> { :Andy }
|
@@ -69,7 +69,7 @@ namespace :profile do
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
desc
|
72
|
+
desc 'Makes all profiling at once'
|
73
73
|
task profile: %i[
|
74
74
|
profile:required
|
75
75
|
profile:defaults
|
data/project.yml
ADDED
data/spec/attributes_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
describe Dry::Initializer,
|
1
|
+
describe Dry::Initializer, 'dry_initializer.attributes' do
|
2
2
|
subject { instance.class.dry_initializer.attributes(instance) }
|
3
3
|
|
4
|
-
context
|
4
|
+
context 'when class has params' do
|
5
5
|
before do
|
6
6
|
class Test::Foo
|
7
7
|
extend Dry::Initializer
|
@@ -13,12 +13,12 @@ describe Dry::Initializer, "dry_initializer.attributes" do
|
|
13
13
|
|
14
14
|
let(:instance) { Test::Foo.new(:FOO) }
|
15
15
|
|
16
|
-
it
|
17
|
-
expect(subject).to eq({ foo:
|
16
|
+
it 'collects coerced params with default values' do
|
17
|
+
expect(subject).to eq({ foo: 'FOO', bar: 1 })
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
context
|
21
|
+
context 'when class has options' do
|
22
22
|
before do
|
23
23
|
class Test::Foo
|
24
24
|
extend Dry::Initializer
|
@@ -31,8 +31,8 @@ describe Dry::Initializer, "dry_initializer.attributes" do
|
|
31
31
|
|
32
32
|
let(:instance) { Test::Foo.new(foo: :FOO, qux: :QUX) }
|
33
33
|
|
34
|
-
it
|
35
|
-
expect(subject).to eq({ foo: :FOO, bar: 1, quxx:
|
34
|
+
it 'collects coerced and renamed options with default values' do
|
35
|
+
expect(subject).to eq({ foo: :FOO, bar: 1, quxx: 'QUX' })
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
describe
|
1
|
+
describe 'coercion of nil' do
|
2
2
|
before do
|
3
3
|
class Test::Foo
|
4
4
|
extend Dry::Initializer
|
@@ -15,11 +15,11 @@ describe "coercion of nil" do
|
|
15
15
|
let(:foo) { Test::Foo.new(nil) }
|
16
16
|
let(:baz) { Test::Baz.new(nil) }
|
17
17
|
|
18
|
-
it
|
18
|
+
it 'works with extend syntax' do
|
19
19
|
expect(foo.bar).to eq 0
|
20
20
|
end
|
21
21
|
|
22
|
-
it
|
22
|
+
it 'works with include syntax' do
|
23
23
|
expect(baz.qux).to eq 0
|
24
24
|
end
|
25
25
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
describe
|
2
|
-
subject { Test::Foo.new
|
1
|
+
describe 'custom dispatchers' do
|
2
|
+
subject { Test::Foo.new '123' }
|
3
3
|
|
4
4
|
before do
|
5
5
|
dispatcher = ->(op) { op[:integer] ? op.merge(type: proc(&:to_i)) : op }
|
6
6
|
Dry::Initializer::Dispatchers << dispatcher
|
7
7
|
end
|
8
8
|
|
9
|
-
context
|
9
|
+
context 'with extend syntax' do
|
10
10
|
before do
|
11
11
|
class Test::Foo
|
12
12
|
extend Dry::Initializer
|
@@ -14,12 +14,12 @@ describe "custom dispatchers" do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
it
|
17
|
+
it 'adds syntax sugar' do
|
18
18
|
expect(subject.id).to eq 123
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
context
|
22
|
+
context 'with include syntax' do
|
23
23
|
before do
|
24
24
|
class Test::Foo
|
25
25
|
include Dry::Initializer.define -> do
|
@@ -28,7 +28,7 @@ describe "custom dispatchers" do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
it
|
31
|
+
it 'adds syntax sugar' do
|
32
32
|
expect(subject.id).to eq 123
|
33
33
|
end
|
34
34
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
describe
|
1
|
+
describe 'custom initializer' do
|
2
2
|
before do
|
3
3
|
class Test::Foo
|
4
4
|
extend Dry::Initializer
|
@@ -21,7 +21,7 @@ describe "custom initializer" do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
it
|
24
|
+
it 'reloads the initializer' do
|
25
25
|
baz = Test::Baz.new(5, 5)
|
26
26
|
|
27
27
|
expect(baz.bar).to eq 15 # 5 * 3
|
data/spec/default_values_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
describe
|
1
|
+
describe 'default values' do
|
2
2
|
before do
|
3
3
|
class Test::Foo
|
4
4
|
extend Dry::Initializer
|
@@ -17,7 +17,7 @@ describe "default values" do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
it
|
20
|
+
it 'instantiate arguments' do
|
21
21
|
subject = Test::Foo.new(1, 2, baz: 3, qux: 4)
|
22
22
|
|
23
23
|
expect(subject.foo).to eql 1
|
@@ -26,7 +26,7 @@ describe "default values" do
|
|
26
26
|
expect(subject.qux).to eql 4
|
27
27
|
end
|
28
28
|
|
29
|
-
it
|
29
|
+
it 'applies default values' do
|
30
30
|
subject = Test::Foo.new
|
31
31
|
|
32
32
|
expect(subject.foo).to eql :FOO
|
@@ -35,7 +35,7 @@ describe "default values" do
|
|
35
35
|
expect(subject.qux).to eql :FOO
|
36
36
|
end
|
37
37
|
|
38
|
-
it
|
38
|
+
it 'applies default values partially' do
|
39
39
|
subject = Test::Foo.new 1, baz: 3
|
40
40
|
|
41
41
|
expect(subject.foo).to eql 1
|
@@ -44,12 +44,12 @@ describe "default values" do
|
|
44
44
|
expect(subject.qux).to eql 1
|
45
45
|
end
|
46
46
|
|
47
|
-
it
|
47
|
+
it 'applies default values from private methods' do
|
48
48
|
subject = Test::Foo.new
|
49
49
|
expect(subject.mox).to eql :MOX
|
50
50
|
end
|
51
51
|
|
52
|
-
describe
|
52
|
+
describe 'when the last param has a default and there are no options' do
|
53
53
|
before do
|
54
54
|
class Test::Bar
|
55
55
|
extend Dry::Initializer
|
@@ -59,21 +59,21 @@ describe "default values" do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
it
|
62
|
+
it 'instantiates arguments' do
|
63
63
|
subject = Test::Bar.new(1, 2)
|
64
64
|
|
65
65
|
expect(subject.foo).to eql 1
|
66
66
|
expect(subject.bar).to eql 2
|
67
67
|
end
|
68
68
|
|
69
|
-
it
|
69
|
+
it 'applies default values' do
|
70
70
|
subject = Test::Bar.new(1)
|
71
71
|
|
72
72
|
expect(subject.foo).to eql 1
|
73
73
|
expect(subject.bar).to eql({})
|
74
74
|
end
|
75
75
|
|
76
|
-
it
|
76
|
+
it 'instantiates arguments also if the last is an hash' do
|
77
77
|
subject = Test::Bar.new(1, { baz: 2, qux: 3 })
|
78
78
|
|
79
79
|
expect(subject.foo).to eql 1
|
data/spec/definition_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
describe
|
1
|
+
describe 'definition' do
|
2
2
|
shared_examples :initializer do |in_context|
|
3
3
|
subject { Test::Foo.new(1, bar: 2) }
|
4
4
|
|
@@ -8,7 +8,7 @@ describe "definition" do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
it_behaves_like :initializer,
|
11
|
+
it_behaves_like :initializer, 'extend Dry::Initializer' do
|
12
12
|
before do
|
13
13
|
class Test::Foo
|
14
14
|
extend Dry::Initializer
|
@@ -17,7 +17,7 @@ describe "definition" do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
it
|
20
|
+
it 'preservers definition params' do
|
21
21
|
params = Test::Foo.dry_initializer.params.map do |definition|
|
22
22
|
[definition.source, definition.options]
|
23
23
|
end
|
@@ -27,7 +27,7 @@ describe "definition" do
|
|
27
27
|
]
|
28
28
|
end
|
29
29
|
|
30
|
-
it
|
30
|
+
it 'preservers definition options' do
|
31
31
|
options = Test::Foo.dry_initializer.options.map do |definition|
|
32
32
|
[definition.source, definition.options]
|
33
33
|
end
|
@@ -38,7 +38,7 @@ describe "definition" do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
it_behaves_like :initializer,
|
41
|
+
it_behaves_like :initializer, 'extend Dry::Initializer' do
|
42
42
|
before do
|
43
43
|
class Test::Foo
|
44
44
|
extend Dry::Initializer
|
@@ -48,7 +48,7 @@ describe "definition" do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
it_behaves_like :initializer,
|
51
|
+
it_behaves_like :initializer, 'extend Dry::Initializer[undefined: false]' do
|
52
52
|
before do
|
53
53
|
class Test::Foo
|
54
54
|
extend Dry::Initializer[undefined: false]
|
@@ -58,7 +58,7 @@ describe "definition" do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
it_behaves_like :initializer,
|
61
|
+
it_behaves_like :initializer, 'include Dry::Initializer with block' do
|
62
62
|
before do
|
63
63
|
class Test::Foo
|
64
64
|
include(
|
@@ -71,7 +71,7 @@ describe "definition" do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
it_behaves_like :initializer,
|
74
|
+
it_behaves_like :initializer, 'include Dry::Initializer with lambda' do
|
75
75
|
before do
|
76
76
|
class Test::Foo
|
77
77
|
include Dry::Initializer.define -> do
|
@@ -82,7 +82,7 @@ describe "definition" do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
it_behaves_like :initializer,
|
85
|
+
it_behaves_like :initializer, 'include Dry::Initializer[undefined: false]' do
|
86
86
|
before do
|
87
87
|
class Test::Foo
|
88
88
|
include(
|
@@ -96,7 +96,7 @@ describe "definition" do
|
|
96
96
|
end
|
97
97
|
|
98
98
|
# @deprecated
|
99
|
-
it_behaves_like :initializer,
|
99
|
+
it_behaves_like :initializer, 'include Dry::Initializer::Mixin' do
|
100
100
|
before do
|
101
101
|
class Test::Foo
|
102
102
|
include(
|
@@ -1,4 +1,4 @@
|
|
1
|
-
describe
|
1
|
+
describe 'invalid default value assignment' do
|
2
2
|
subject do
|
3
3
|
class Test::Foo
|
4
4
|
extend Dry::Initializer
|
@@ -7,7 +7,7 @@ describe "invalid default value assignment" do
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
it
|
10
|
+
it 'raises TypeError' do
|
11
11
|
expect { subject }.to raise_error TypeError
|
12
12
|
end
|
13
13
|
end
|
data/spec/list_type_spec.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
require
|
1
|
+
require 'dry-types'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe 'list type argument' do
|
4
4
|
before do
|
5
5
|
class Test::Foo
|
6
6
|
extend Dry::Initializer
|
7
7
|
param :foo, [proc(&:to_s)]
|
8
|
-
option :bar, [Dry::Types[
|
8
|
+
option :bar, [Dry::Types['strict.string']]
|
9
9
|
option :baz, []
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
context
|
14
|
-
subject { Test::Foo.new(1, bar:
|
13
|
+
context 'with single items' do
|
14
|
+
subject { Test::Foo.new(1, bar: '2', baz: { qux: :QUX }) }
|
15
15
|
|
16
|
-
it
|
16
|
+
it 'coerces and wraps them to arrays' do
|
17
17
|
expect(subject.foo).to eq %w[1]
|
18
18
|
expect(subject.bar).to eq %w[2]
|
19
19
|
expect(subject.baz).to eq [{ qux: :QUX }]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
context
|
23
|
+
context 'with arrays' do
|
24
24
|
subject { Test::Foo.new([1], bar: %w[2], baz: [{ qux: :QUX }]) }
|
25
25
|
|
26
|
-
it
|
26
|
+
it 'coerces elements' do
|
27
27
|
expect(subject.foo).to eq %w[1]
|
28
28
|
expect(subject.bar).to eq %w[2]
|
29
29
|
expect(subject.baz).to eq [{ qux: :QUX }]
|
data/spec/missed_default_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
describe
|
1
|
+
describe 'missed default values' do
|
2
2
|
subject do
|
3
3
|
class Test::Foo
|
4
4
|
extend Dry::Initializer
|
@@ -8,7 +8,7 @@ describe "missed default values" do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
it
|
11
|
+
it 'raises SyntaxError' do
|
12
12
|
expect { subject }.to raise_error SyntaxError, /bar/
|
13
13
|
end
|
14
14
|
end
|
data/spec/nested_type_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
describe
|
2
|
-
subject { Test::Xyz.new(
|
1
|
+
describe 'nested type argument' do
|
2
|
+
subject { Test::Xyz.new('bar' => { 'baz' => 42 }) }
|
3
3
|
|
4
|
-
context
|
4
|
+
context 'with nested definition only' do
|
5
5
|
before do
|
6
6
|
class Test::Xyz
|
7
7
|
extend Dry::Initializer
|
@@ -15,16 +15,16 @@ describe "nested type argument" do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
it
|
19
|
-
expect(subject.x.y.z).to eq
|
18
|
+
it 'builds the type' do
|
19
|
+
expect(subject.x.y.z).to eq '42'
|
20
20
|
end
|
21
21
|
|
22
|
-
it
|
23
|
-
expect(subject.x.to_h).to eq(
|
22
|
+
it 'converts the nested type to hash' do
|
23
|
+
expect(subject.x.to_h).to eq('y' => { 'z' => '42' })
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
context
|
27
|
+
context 'with nested and wrapped definitions' do
|
28
28
|
before do
|
29
29
|
class Test::Xyz
|
30
30
|
extend Dry::Initializer
|
@@ -38,11 +38,11 @@ describe "nested type argument" do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
it
|
41
|
+
it 'builds the type' do
|
42
42
|
x = subject.x
|
43
43
|
expect(x).to be_instance_of Array
|
44
44
|
|
45
|
-
expect(x.first.y.z).to eq
|
45
|
+
expect(x.first.y.z).to eq '42'
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|