dry-initializer 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +234 -242
  3. data/dry-initializer.gemspec +28 -15
  4. data/lib/dry/initializer/builders/attribute.rb +1 -1
  5. data/lib/dry/initializer/version.rb +1 -1
  6. metadata +24 -104
  7. data/.codeclimate.yml +0 -12
  8. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  9. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
  10. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  11. data/.github/workflows/custom_ci.yml +0 -58
  12. data/.github/workflows/docsite.yml +0 -34
  13. data/.github/workflows/sync_configs.yml +0 -56
  14. data/.gitignore +0 -12
  15. data/.rspec +0 -4
  16. data/.rubocop.yml +0 -102
  17. data/CODE_OF_CONDUCT.md +0 -13
  18. data/CONTRIBUTING.md +0 -29
  19. data/Gemfile +0 -36
  20. data/Gemfile.devtools +0 -16
  21. data/Guardfile +0 -5
  22. data/LICENSE.txt +0 -21
  23. data/Rakefile +0 -8
  24. data/benchmarks/compare_several_defaults.rb +0 -82
  25. data/benchmarks/plain_options.rb +0 -63
  26. data/benchmarks/plain_params.rb +0 -84
  27. data/benchmarks/with_coercion.rb +0 -71
  28. data/benchmarks/with_defaults.rb +0 -66
  29. data/benchmarks/with_defaults_and_coercion.rb +0 -59
  30. data/bin/.gitkeep +0 -0
  31. data/docsite/source/attributes.html.md +0 -106
  32. data/docsite/source/container-version.html.md +0 -39
  33. data/docsite/source/index.html.md +0 -43
  34. data/docsite/source/inheritance.html.md +0 -43
  35. data/docsite/source/optionals-and-defaults.html.md +0 -130
  36. data/docsite/source/options-tolerance.html.md +0 -27
  37. data/docsite/source/params-and-options.html.md +0 -74
  38. data/docsite/source/rails-support.html.md +0 -101
  39. data/docsite/source/readers.html.md +0 -43
  40. data/docsite/source/skip-undefined.html.md +0 -59
  41. data/docsite/source/type-constraints.html.md +0 -160
  42. data/project.yml +0 -2
  43. data/spec/attributes_spec.rb +0 -38
  44. data/spec/coercion_of_nil_spec.rb +0 -25
  45. data/spec/custom_dispatchers_spec.rb +0 -35
  46. data/spec/custom_initializer_spec.rb +0 -30
  47. data/spec/default_values_spec.rb +0 -83
  48. data/spec/definition_spec.rb +0 -111
  49. data/spec/invalid_default_spec.rb +0 -13
  50. data/spec/list_type_spec.rb +0 -32
  51. data/spec/missed_default_spec.rb +0 -14
  52. data/spec/nested_type_spec.rb +0 -48
  53. data/spec/optional_spec.rb +0 -71
  54. data/spec/options_tolerance_spec.rb +0 -11
  55. data/spec/public_attributes_utility_spec.rb +0 -22
  56. data/spec/reader_spec.rb +0 -87
  57. data/spec/repetitive_definitions_spec.rb +0 -69
  58. data/spec/several_assignments_spec.rb +0 -41
  59. data/spec/spec_helper.rb +0 -24
  60. data/spec/subclassing_spec.rb +0 -49
  61. data/spec/support/coverage.rb +0 -7
  62. data/spec/support/warnings.rb +0 -7
  63. data/spec/type_argument_spec.rb +0 -35
  64. data/spec/type_constraint_spec.rb +0 -96
  65. data/spec/value_coercion_via_dry_types_spec.rb +0 -29
@@ -1,71 +0,0 @@
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)
8
- option :bar, proc(&:to_s)
9
- end
10
-
11
- class DryTestUndefined
12
- extend Dry::Initializer
13
-
14
- option :foo, proc(&:to_s)
15
- option :bar, proc(&:to_s)
16
- end
17
-
18
- class PlainRubyTest
19
- attr_reader :foo, :bar
20
-
21
- def initialize(options)
22
- @foo = options[:foo].to_s
23
- @bar = options[:bar].to_s
24
- end
25
- end
26
-
27
- require 'virtus'
28
- class VirtusTest
29
- include Virtus.model
30
-
31
- attribute :foo, String
32
- attribute :bar, String
33
- end
34
-
35
- require 'fast_attributes'
36
- class FastAttributesTest
37
- extend FastAttributes
38
-
39
- define_attributes initialize: true do
40
- attribute :foo, String
41
- attribute :bar, String
42
- end
43
- end
44
-
45
- puts 'Benchmark for instantiation with coercion'
46
-
47
- Benchmark.ips do |x|
48
- x.config time: 15, warmup: 10
49
-
50
- x.report('plain Ruby') do
51
- PlainRubyTest.new foo: 'FOO', bar: 'BAR'
52
- end
53
-
54
- x.report('dry-initializer') do
55
- DryTest.new foo: 'FOO', bar: 'BAR'
56
- end
57
-
58
- x.report('dry-initializer (with UNDEFINED)') do
59
- DryTestUndefined.new foo: 'FOO', bar: 'BAR'
60
- end
61
-
62
- x.report('virtus') do
63
- VirtusTest.new foo: 'FOO', bar: 'BAR'
64
- end
65
-
66
- x.report('fast_attributes') do
67
- FastAttributesTest.new foo: 'FOO', bar: 'BAR'
68
- end
69
-
70
- x.compare!
71
- end
@@ -1,66 +0,0 @@
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
@@ -1,59 +0,0 @@
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
File without changes
@@ -1,106 +0,0 @@
1
- ---
2
- title: Attributes
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- Sometimes you need to access all attributes assigned via params and options of the object constructor.
8
-
9
- We support 2 methods: `attributes` and `public_attributes` for this goal. Both methods are wrapped into container accessible via `.dry_types` container:
10
-
11
- ```ruby
12
- require 'dry-initializer'
13
-
14
- class User
15
- extend Dry::Initializer
16
-
17
- param :name
18
- option :email, optional: true
19
- option :telefon, optional: true, as: :phone
20
- end
21
-
22
- user = User.new "Andy", telefon: "71002003040"
23
-
24
- User.dry_initializer.attributes(user)
25
- # => { name: "Andy", phone: "71002003040" }
26
- ```
27
-
28
- What the method does is extracts *variables assigned* to the object (and skips unassigned ones like the `email` above). It doesn't matter whether you send it via `params` or `option`; we look at the result of the instantiation, not at the interface.
29
-
30
- Method `public_attributes` works different. Let's look at the following example to see the difference:
31
-
32
- ```ruby
33
- require 'dry-initializer'
34
-
35
- class User
36
- extend Dry::Initializer
37
-
38
- param :name
39
- option :telefon, optional: true, as: :phone
40
- option :email, optional: true
41
- option :token, optional: true, reader: :private
42
- option :password, optional: true, reader: false
43
- end
44
-
45
- user = User.new "Andy", telefon: "71002003040", token: "foo", password: "bar"
46
-
47
- User.dry_initializer.attributes(user)
48
- # => { name: "Andy", phone: "71002003040", token: "foo", password: "bar" }
49
-
50
- User.dry_initializer.public_attributes(user)
51
- # => { name: "Andy", phone: "71002003040", email: nil }
52
- ```
53
-
54
- Notice that `public_attribute` reads *public reader methods*, not variables. That's why it skips both the private `token`, and the `password` whose reader hasn't been defined.
55
-
56
- Another difference concerns unassigned values. Because the reader `user.email` returns `nil` (its `@email` variable contains `Dry::Initializer::UNDEFINED` constant), the `public_attributes` adds this value to the hash using the method.
57
-
58
- The third thing to mention is that you can override the reader, and it is the overriden method which will be used by `public_attributes`:
59
-
60
- ```ruby
61
- require 'dry-initializer'
62
-
63
- class User
64
- extend Dry::Initializer
65
-
66
- param :name
67
- option :password, optional: true
68
-
69
- def password
70
- super.hash.to_s
71
- end
72
- end
73
-
74
- user = User.new "Joe", password: "foo"
75
-
76
- User.dry_initializer.attributes(user)
77
- # => { user: "Joe", password: "foo" }
78
-
79
- User.dry_initializer.public_attributes(user)
80
- # => { user: "Joe", password: "-1844874613000160009" }
81
- ```
82
-
83
- This feature works for the "extend Dry::Initializer" syntax. But what about "include Dry::Initializer.define ..."? Now we don't pollute class namespace with new methods, that's why `.dry_initializer` is absent.
84
-
85
- To access config you can use a hack. Under the hood we define private instance method `#__dry_initializer_config__` which refers to the same container. So you can write:
86
-
87
- ```ruby
88
- require 'dry-initializer'
89
-
90
- class User
91
- extend Dry::Initializer
92
- param :name
93
- end
94
-
95
- user = User.new "Joe"
96
-
97
- user.send(:__dry_initializer_config__).attributes(user)
98
- # => { user: "Joe" }
99
-
100
- user.send(:__dry_initializer_config__).public_attributes(user)
101
- # => { user: "Joe" }
102
- ```
103
-
104
- This is a hack because the `__dry_initializer_config__` is not a part of the gem's public interface; there's a possibility it can be changed or removed in the later releases.
105
-
106
- We'll try to be careful with it, and mark it as deprecated method in case of such a removal.
@@ -1,39 +0,0 @@
1
- ---
2
- title: Container Version
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- Instead of extending a class with the `Dry::Initializer`, you can include a container with the `initializer` method only. This method should be preferred when you don't need subclassing.
8
-
9
- ```ruby
10
- require 'dry-initializer'
11
-
12
- class User
13
- # notice `-> do .. end` syntax
14
- include Dry::Initializer.define -> do
15
- param :name, proc(&:to_s)
16
- param :role, default: proc { 'customer' }
17
- option :admin, default: proc { false }
18
- end
19
- end
20
- ```
21
-
22
- If you still need the DSL (`param` and `option`) to be inherited, use the direct extension:
23
-
24
- ```ruby
25
- require 'dry-initializer'
26
-
27
- class BaseService
28
- extend Dry::Initializer
29
- alias_method :dependency, :param
30
- end
31
-
32
- class ShowUser < BaseService
33
- dependency :user
34
-
35
- def call
36
- puts user&.name
37
- end
38
- end
39
- ```
@@ -1,43 +0,0 @@
1
- ---
2
- title: Introduction & Usage
3
- description: DSL for defining initializer params and options
4
- layout: gem-single
5
- order: 8
6
- type: gem
7
- name: dry-initializer
8
- sections:
9
- - container-version
10
- - params-and-options
11
- - options-tolerance
12
- - optionals-and-defaults
13
- - type-constraints
14
- - readers
15
- - inheritance
16
- - skip-undefined
17
- - attributes
18
- - rails-support
19
- ---
20
-
21
- `dry-initializer` is a simple mixin of class methods `params` and `options` for instances.
22
-
23
- ## Synopsis
24
-
25
- ```ruby
26
- require 'dry-initializer'
27
-
28
- class User
29
- extend Dry::Initializer
30
-
31
- param :name, proc(&:to_s)
32
- param :role, default: proc { 'customer' }
33
- option :admin, default: proc { false }
34
- option :phone, optional: true
35
- end
36
-
37
- user = User.new 'Vladimir', 'admin', admin: true
38
-
39
- user.name # => 'Vladimir'
40
- user.role # => 'admin'
41
- user.admin # => true
42
- user.phone # => nil
43
- ```
@@ -1,43 +0,0 @@
1
- ---
2
- title: Inheritance
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- Subclassing preserves all definitions being made inside a superclass.
8
-
9
- ```ruby
10
- require 'dry-initializer'
11
-
12
- class User
13
- extend Dry::Initializer
14
-
15
- param :name
16
- end
17
-
18
- class Employee < User
19
- param :position
20
- end
21
-
22
- employee = Employee.new('John', 'supercargo')
23
- employee.name # => 'John'
24
- employee.position # => 'supercargo'
25
-
26
- employee = Employee.new # => fails because type
27
- ```
28
-
29
- You can override params and options.
30
- Such overriding leaves initial order of params (positional arguments) unchanged:
31
-
32
- ```ruby
33
- class Employee < User
34
- param :position, optional: true
35
- param :name, default: proc { 'Unknown' }
36
- end
37
-
38
- user = User.new # => Boom! because User#name is required
39
- employee = Employee.new # passes because who cares on employee's name
40
-
41
- employee.name
42
- # => 'Unknown' because it is the name that positioned first like in User
43
- ```
@@ -1,130 +0,0 @@
1
- ---
2
- title: Optional Attributes and Default Values
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- By default both params and options are mandatory. Use `:default` key to make them optional:
8
-
9
- ```ruby
10
- require 'dry-initializer'
11
-
12
- class User
13
- extend Dry::Initializer
14
-
15
- param :name, default: proc { 'Unknown user' }
16
- option :email, default: proc { 'unknown@example.com' }
17
- option :phone, optional: true
18
- end
19
-
20
- user = User.new
21
- user.name # => 'Unknown user'
22
- user.email # => 'unknown@example.com'
23
- user.phone # => Dry::Initializer::UNDEFINED
24
-
25
- user = User.new 'Vladimir', email: 'vladimir@example.com', phone: '71234567788'
26
- user.name # => 'Vladimir'
27
- user.email # => 'vladimir@example.com'
28
- user.phone # => '71234567788'
29
- ```
30
-
31
- You cannot define required **parameter** after optional one. The following example raises `SyntaxError` exception:
32
-
33
- ```ruby
34
- require 'dry-initializer'
35
-
36
- class User
37
- extend Dry::Initializer
38
-
39
- param :name, default: proc { 'Unknown name' }
40
- param :email # => #<SyntaxError ...>
41
- end
42
- ```
43
-
44
- You should assign `nil` value explicitly. Otherwise an instance variable it will be left undefined. In both cases attribute reader method will return `nil`.
45
-
46
- ```ruby
47
- require 'dry-initializer'
48
-
49
- class User
50
- extend Dry::Initializer
51
-
52
- param :name
53
- option :email, optional: true
54
- end
55
-
56
- user = User.new 'Andrew'
57
- user.email # => nil
58
- user.instance_variable_get :@email
59
- # => Dry::Initializer::UNDEFINED
60
-
61
- user = User.new 'Andrew', email: nil
62
- user.email # => nil
63
- user.instance_variable_get :@email
64
- # => nil
65
- ```
66
-
67
- You can also set `nil` as a default value:
68
-
69
- ```ruby
70
- require 'dry-initializer'
71
-
72
- class User
73
- extend Dry::Initializer
74
-
75
- param :name
76
- option :email, default: proc { nil }
77
- end
78
-
79
- user = User.new 'Andrew'
80
- user.email # => nil
81
- user.instance_variable_get :@email
82
- # => nil
83
- ```
84
-
85
- You **must** wrap default values into procs.
86
-
87
- If you need to **assign** proc as a default value, wrap it to another one:
88
-
89
- ```ruby
90
- require 'dry-initializer'
91
-
92
- class User
93
- extend Dry::Initializer
94
-
95
- param :name_proc, default: proc { proc { 'Unknown user' } }
96
- end
97
-
98
- user = User.new
99
- user.name_proc.call # => 'Unknown user'
100
- ```
101
-
102
- Proc will be executed in a scope of new instance. You can refer to other arguments:
103
-
104
- ```ruby
105
- require 'dry-initializer'
106
-
107
- class User
108
- extend Dry::Initializer
109
-
110
- param :name
111
- param :email, default: proc { "#{name.downcase}@example.com" }
112
- end
113
-
114
- user = User.new 'Andrew'
115
- user.email # => 'andrew@example.com'
116
- ```
117
-
118
- **Warning**: when using lambdas instead of procs, don't forget an argument, required by [instance_eval][instance_eval] (you can skip in in a proc).
119
-
120
- ```ruby
121
- require 'dry-initializer'
122
-
123
- class User
124
- extend Dry::Initializer
125
-
126
- param :name, default: -> (obj) { 'Dude' }
127
- end
128
- ```
129
-
130
- [instance_eval]: http://ruby-doc.org/core-2.2.0/BasicObject.html#method-i-instance_eval