dry-initializer 3.0.2 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|