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,27 +0,0 @@
1
- ---
2
- title: Tolerance to Unknown Options
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- By default the initializer is strict for params (positional arguments), expecting them to be defined explicitly.
8
-
9
- ```ruby
10
- require 'dry-initializer'
11
-
12
- class User
13
- extend Dry::Initializer
14
- end
15
-
16
- user = User.new 'Joe' # raises ArgumentError
17
- ```
18
-
19
- At the same time it is tolerant to unknown options. All unknown options are accepted, but ignored:
20
-
21
- ```ruby
22
- # It accepts undefined options...
23
- user = User.new name: 'Joe'
24
-
25
- # ...but ignores them
26
- user.respond_to? :name # => false
27
- ```
@@ -1,74 +0,0 @@
1
- ---
2
- title: Params and Options
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- Use `param` to define plain argument:
8
-
9
- ```ruby
10
- require 'dry-initializer'
11
-
12
- class User
13
- extend Dry::Initializer
14
-
15
- param :name
16
- param :email
17
- end
18
-
19
- user = User.new 'Andrew', 'andrew@email.com'
20
- user.name # => 'Andrew'
21
- user.email # => 'andrew@email.com'
22
- ```
23
-
24
- Use `option` to define named (hash) argument:
25
-
26
- ```ruby
27
- require 'dry-initializer'
28
-
29
- class User
30
- extend Dry::Initializer
31
-
32
- option :name
33
- option :email
34
- end
35
-
36
- user = User.new email: 'andrew@email.com', name: 'Andrew'
37
- user.name # => 'Andrew'
38
- user.email # => 'andrew@email.com'
39
- ```
40
-
41
- Options can be renamed using `:as` key:
42
-
43
- ```ruby
44
- require 'dry-initializer'
45
-
46
- class User
47
- extend Dry::Initializer
48
-
49
- option :name, as: :username
50
- end
51
-
52
- user = User.new name: "Joe"
53
- user.username # => "Joe"
54
- user.instance_variable_get :@username # => "Joe"
55
- user.instance_variable_get :@name # => nil
56
- user.respond_to? :name # => false
57
- ```
58
-
59
- You can also define several ways of initializing the same argument via different options:
60
-
61
- ```ruby
62
- require 'dry-initializer'
63
-
64
- class User
65
- extend Dry::Initializer
66
-
67
- option :phone
68
- option :telephone, as: :phone
69
- option :name, optional: true
70
- end
71
-
72
- User.new(phone: '1234567890').phone # => '1234567890'
73
- User.new(telephone: '1234567890').phone # => '1234567890'
74
- ```
@@ -1,101 +0,0 @@
1
- ---
2
- title: Rails Support
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- Rails plugin is implemented in a separate [dry-initializer-rails](https://github.com/nepalez/dry-initializer-rails) gem.
8
-
9
- It provides coercion of assigned values to corresponding ActiveRecord instances.
10
-
11
- ### Base Example
12
-
13
- Add the `:model` setting to `param` or `option`:
14
-
15
- ```ruby
16
- require 'dry-initializer-rails'
17
-
18
- class CreateOrder
19
- extend Dry::Initializer
20
-
21
- # Params and options
22
- param :customer, model: 'Customer' # use either a name
23
- option :product, model: Product # or a class
24
-
25
- def call
26
- Order.create customer: customer, product: product
27
- end
28
- end
29
- ```
30
-
31
- Now you can assign values as pre-initialized model instances:
32
-
33
- ```ruby
34
- customer = Customer.find(1)
35
- product = Product.find(2)
36
-
37
- order = CreateOrder.new(customer, product: product).call
38
- order.customer # => <Customer @id=1 ...>
39
- order.product # => <Product @id=2 ...>
40
- ```
41
-
42
- ...or their ids:
43
-
44
- ```ruby
45
- order = CreateOrder.new(1, product: 2).call
46
- order.customer # => <Customer @id=1 ...>
47
- order.product # => <Product @id=2 ...>
48
- ```
49
-
50
- The instance is envoked using method `find_by(id: ...)`.
51
- With wrong ids `nil` values are assigned to corresponding params and options:
52
-
53
- ```ruby
54
- order = CreateOrder.new(0, product: 0).call
55
- order.customer # => nil
56
- order.product # => nil
57
- ```
58
-
59
- ### Custom Keys
60
-
61
- You can specify custom `key` for searching model instance:
62
-
63
- ```ruby
64
- require 'dry-initializer-rails'
65
-
66
- class CreateOrder
67
- extend Dry::Initializer
68
-
69
- param :customer, model: 'User', find_by: 'name'
70
- option :product, model: Item, find_by: :name
71
- end
72
- ```
73
-
74
- This time you can send names (not ids) to the initializer:
75
-
76
- ```ruby
77
- order = CreateOrder.new('Andrew', product: 'the_thing_no_123').call
78
-
79
- order.customer # => <User @name='Andrew' ...>
80
- order.product # => <Item @name='the_thing_no_123' ...>
81
- ```
82
-
83
- ### Container Syntax
84
-
85
- If you prefer [container syntax](docs::container-version), extend plugin inside the block:
86
-
87
- ```ruby
88
- require 'dry-initializer-rails'
89
-
90
- class CreateOrder
91
- include Dry::Initializer.define -> do
92
- # ... params/options declarations
93
- end
94
- end
95
- ```
96
-
97
- ### Types vs Models
98
-
99
- [Type constraints](docs::type-constraints) are checked before the coercion.
100
-
101
- When mixing `:type` and `:model` settings for the same param/option, you should use [sum types](/gems/dry-types/1.2/sum) that accept both model instances and their attributes.
@@ -1,43 +0,0 @@
1
- ---
2
- title: Readers
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- By default public attribute reader is defined for every param and option.
8
-
9
- You can define private or protected reader instead:
10
-
11
- ```ruby
12
- require 'dry-initializer'
13
-
14
- class User
15
- extend Dry::Initializer
16
-
17
- param :name, reader: :private # the same as adding `private :name`
18
- param :email, reader: :protected # the same as adding `protected :email`
19
- end
20
- ```
21
-
22
- To skip any reader, use `reader: false`:
23
-
24
- ```ruby
25
- require 'dry-initializer'
26
-
27
- class User
28
- extend Dry::Initializer
29
-
30
- param :name
31
- param :email, reader: false
32
- end
33
-
34
- user = User.new 'Luke', 'luke@example.com'
35
- user.name # => 'Luke'
36
-
37
- user.email # => #<NoMethodError ...>
38
- user.instance_variable_get :@email # => 'luke@example.com'
39
- ```
40
-
41
- Notice that any other value except for `false`, `:protected` and `:private` provides a public reader.
42
-
43
- No writers are defined. Define them using pure ruby `attr_writer` when necessary.
@@ -1,59 +0,0 @@
1
- ---
2
- title: Skip Undefined
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- The initializer uses special constant `Dry::Initializer::UNDEFINED` to distinguish variables that are set to `nil` from those that are not set at all.
8
-
9
- When no value was provided, the constant is assigned to a variable, but hidden in a reader.
10
-
11
- ```ruby
12
- require 'dry-initializer'
13
-
14
- class User
15
- extend Dry::Initializer
16
- option :email, optional: true
17
- end
18
-
19
- user = User.new
20
-
21
- user.email
22
- # => nil
23
-
24
- user.instance_variable_get :@email
25
- # => Dry::Initializer::UNDEFINED
26
- ```
27
-
28
- This gives you full control of the real state of the attributes. However, all that checks cost about >30% of instantiation time, and make attribute readers 2 times slower.
29
-
30
- To avoid the overhead in cases you don't care about the differences between `nil` and undefined, you can use a light version of the module. Add `[undefined: false]` config to either `extend` or `include` line of code:
31
-
32
- ```ruby
33
- extend Dry::Initializer[undefined: false]
34
- ```
35
-
36
- ```ruby
37
- include Dry::Initializer[undefined: false] -> do
38
- # ...
39
- end
40
- ```
41
-
42
- This time you should expect `nil` every time no value was given to an optional attribute:
43
-
44
- ```ruby
45
- require 'dry-initializer'
46
-
47
- class User
48
- extend Dry::Initializer[undefined: false]
49
- option :email, optional: true
50
- end
51
-
52
- user = User.new
53
-
54
- user.email
55
- # => nil
56
-
57
- user.instance_variable_get :@email
58
- # => nil
59
- ```
@@ -1,160 +0,0 @@
1
- ---
2
- title: Type Constraints
3
- layout: gem-single
4
- name: dry-initializer
5
- ---
6
-
7
- ## Base Syntax
8
-
9
- Use `:type` key in a `param` or `option` declarations to add type coercer.
10
-
11
- ```ruby
12
- require 'dry-initializer'
13
-
14
- class User
15
- extend Dry::Initializer
16
- param :name, type: proc(&:to_s)
17
- end
18
-
19
- user = User.new :Andrew
20
- user.name # => "Andrew"
21
- ```
22
-
23
- Any object that responds to `#call` with 1 argument can be used as a type. Common examples are `proc(&:to_s)` for strings, `method(:Array)` (for arrays) or `Array.method(:wrap)` in Rails, `->(v) { !!v }` (for booleans), etc.
24
-
25
- ## Dry Types as coercers
26
-
27
- Another important example is the usage of `dry-types` as type constraints:
28
-
29
- ```ruby
30
- require 'dry-initializer'
31
- require 'dry-types'
32
-
33
- class User
34
- extend Dry::Initializer
35
- param :name, type: Dry::Types['strict.string']
36
- end
37
-
38
- user = User.new :Andrew # => #<TypeError ...>
39
- ```
40
-
41
- ## Positional Argument
42
-
43
- Instead of `:type` option you can send a constraint/coercer as the second argument:
44
-
45
- ```ruby
46
- require 'dry-initializer'
47
- require 'dry-types'
48
-
49
- class User
50
- extend Dry::Initializer
51
- param :name, Dry::Types['coercible.string']
52
- param :email, proc(&:to_s)
53
- end
54
- ```
55
-
56
- ## Array Types
57
-
58
- As mentioned above, the `:type` option takes a callable object... with one important exception.
59
-
60
- You can use arrays for values that should be wrapped to array:
61
-
62
- ```ruby
63
- class User
64
- extend Dry::Initializer
65
-
66
- option :name, proc(&:to_s)
67
- option :emails, [proc(&:to_s)]
68
- end
69
-
70
- user = User.new name: "joe", emails: :"joe@example.com"
71
- user.emails # => ["joe@example.com"]
72
-
73
- user = User.new name: "jane", emails: [:"jane@example.com", :"jane@example.org"]
74
- user.emails # => ["jane@example.com", "jane@example.org"]
75
- ```
76
-
77
- You can wrap the coercer into several arrays as well:
78
-
79
- ```ruby
80
- class User
81
- extend Dry::Initializer
82
-
83
- option :emails, [[proc(&:to_s)]]
84
- end
85
-
86
- user = User.new name: "joe", emails: "joe@example.com"
87
- user.emails # => [["joe@example.com"]]
88
- ```
89
-
90
- Eventually, you can use an empty array as a coercer. In that case we just wrap the source value(s) into array, not modifying the items:
91
-
92
- ```ruby
93
- class Article
94
- extend Dry::Initializer
95
-
96
- option :tags, []
97
- end
98
-
99
- article = Article.new(tags: 1)
100
- article.tags # => [1]
101
- ```
102
-
103
- ## Nested Options
104
-
105
- Sometimes you need to describe a structure with nested options. In this case you can use a block with `options` inside.
106
-
107
- ```ruby
108
- class User
109
- extend Dry::Initializer
110
-
111
- option :name, proc(&:to_s)
112
-
113
- option :emails, [] do
114
- option :address, proc(&:to_s)
115
- option :description, proc(&:to_s)
116
- end
117
- end
118
-
119
- user = User.new name: "joe",
120
- emails: { address: "joe@example.com", description: "Job email" }
121
-
122
- user.emails.class # => Array
123
- user.emails.first.class # => User::Emails
124
- user.emails.first.address # => "joe@example.com"
125
-
126
- user.emails.to_h # => [{ address: "joe@example.com", description: "Job email" }]
127
- ```
128
-
129
- Notice how we mixed array wrapper with a nested type.
130
-
131
- The only syntax restriction here is that you cannot use a positional `param` _inside_ the block.
132
-
133
- ## Back References
134
-
135
- Sometimes you need to refer back to the initialized instance. In this case use a second argument to explicitly give the instance to a coercer:
136
-
137
- ```ruby
138
- class Location < String
139
- attr_reader :parameter # refers back to its parameter
140
-
141
- def initialize(name, parameter)
142
- super(name)
143
- @parameter = parameter
144
- end
145
- end
146
-
147
- class Parameter
148
- extend Dry::Initializer
149
- param :name
150
- param :location, ->(value, param) { Location.new(value, param) }
151
- end
152
-
153
- offset = Parameter.new "offset", location: "query"
154
- offset.name # => "offset"
155
- offset.location # => "query"
156
- offset.location.parameter == offset # true
157
- ```
158
-
159
- [dry-types]: https://github.com/dry-rb/dry-types
160
- [dry-types-docs]: http://dry-rb.org/gems/dry-types/