dry-initializer 0.1.1 → 0.2.0
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/.rubocop.yml +13 -9
- data/CHANGELOG.md +72 -3
- data/LICENSE.txt +1 -1
- data/README.md +7 -279
- data/benchmarks/with_types.rb +2 -0
- data/benchmarks/with_types_and_defaults.rb +2 -0
- data/dry-initializer.gemspec +1 -1
- data/lib/dry/initializer.rb +5 -4
- data/lib/dry/initializer/builder.rb +66 -13
- data/lib/dry/initializer/errors.rb +5 -7
- data/lib/dry/initializer/errors/default_value_error.rb +6 -0
- data/lib/dry/initializer/errors/order_error.rb +7 -0
- data/lib/dry/initializer/errors/plugin_error.rb +6 -0
- data/lib/dry/initializer/errors/{existing_argument_error.rb → redefinition_error.rb} +1 -1
- data/lib/dry/initializer/errors/type_constraint_error.rb +6 -0
- data/lib/dry/initializer/errors/type_error.rb +4 -3
- data/lib/dry/initializer/mixin.rb +7 -7
- data/lib/dry/initializer/plugins.rb +10 -0
- data/lib/dry/initializer/plugins/base.rb +42 -0
- data/lib/dry/initializer/plugins/default_proc.rb +28 -0
- data/lib/dry/initializer/plugins/signature.rb +35 -0
- data/lib/dry/initializer/plugins/type_constraint.rb +58 -0
- data/lib/dry/initializer/plugins/variable_setter.rb +12 -0
- data/lib/dry/initializer/signature.rb +47 -0
- data/spec/dry/container_spec.rb +3 -3
- data/spec/dry/dry_type_constraint_spec.rb +30 -0
- data/spec/dry/invalid_default_spec.rb +1 -1
- data/spec/dry/{proc_type_spec.rb → object_type_constraint_spec.rb} +4 -4
- data/spec/dry/{poro_type_spec.rb → plain_type_constraint_spec.rb} +1 -1
- data/spec/dry/value_coercion_via_dry_types_spec.rb +21 -0
- metadata +29 -25
- data/lib/dry/initializer/argument.rb +0 -96
- data/lib/dry/initializer/arguments.rb +0 -85
- data/lib/dry/initializer/errors/invalid_default_value_error.rb +0 -6
- data/lib/dry/initializer/errors/invalid_type_error.rb +0 -6
- data/lib/dry/initializer/errors/key_error.rb +0 -5
- data/lib/dry/initializer/errors/missed_default_value_error.rb +0 -5
- data/spec/dry/dry_type_spec.rb +0 -25
- data/spec/dry/invalid_type_spec.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a155e17b7e2f0fb9274bf3b6511c64380784ae90
|
4
|
+
data.tar.gz: 967ba81a147fa585ba889b3e97378a3340db312a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af677c57dc5ca40e7c2d3540cb566e145643daecf2eb564c752f95b3123f74bfed8320edecf9764cb933cd007ee7421728e1965941f122187dcdbd7ff0b830bd
|
7
|
+
data.tar.gz: 7d8d21a38ff8a0cb08a41ee8e3c37665a020a1314bb59851f3c85d3eff58b96196a105c8a32c8f9b46bb8961f5c2681122c578fe6a01d481d270d02a2a956944
|
data/.rubocop.yml
CHANGED
@@ -7,20 +7,20 @@ AllCops:
|
|
7
7
|
|
8
8
|
Lint/HandleExceptions:
|
9
9
|
Exclude:
|
10
|
-
-
|
10
|
+
- spec/**/*_spec.rb
|
11
11
|
|
12
12
|
Lint/RescueException:
|
13
13
|
Exclude:
|
14
|
-
-
|
14
|
+
- spec/**/*_spec.rb
|
15
15
|
|
16
16
|
Metrics/LineLength:
|
17
17
|
Max: 80
|
18
18
|
Exclude:
|
19
|
-
-
|
19
|
+
- spec/**/*_spec.rb
|
20
20
|
|
21
21
|
Style/AccessorMethodName:
|
22
22
|
Exclude:
|
23
|
-
-
|
23
|
+
- spec/**/*_spec.rb
|
24
24
|
|
25
25
|
Style/Alias:
|
26
26
|
EnforcedStyle: prefer_alias_method
|
@@ -52,6 +52,10 @@ Style/EmptyLineBetweenDefs:
|
|
52
52
|
Style/FileName:
|
53
53
|
Enabled: false
|
54
54
|
|
55
|
+
Style/Lambda:
|
56
|
+
Exclude:
|
57
|
+
- spec/**/*_spec.rb
|
58
|
+
|
55
59
|
Style/ModuleFunction:
|
56
60
|
Enabled: false
|
57
61
|
|
@@ -60,7 +64,7 @@ Style/RaiseArgs:
|
|
60
64
|
|
61
65
|
Style/Semicolon:
|
62
66
|
Exclude:
|
63
|
-
-
|
67
|
+
- spec/**/*_spec.rb
|
64
68
|
|
65
69
|
Style/SignalException:
|
66
70
|
EnforcedStyle: semantic
|
@@ -70,15 +74,15 @@ Style/SingleLineBlockParams:
|
|
70
74
|
|
71
75
|
Style/SingleLineMethods:
|
72
76
|
Exclude:
|
73
|
-
-
|
77
|
+
- spec/**/*_spec.rb
|
74
78
|
|
75
79
|
Style/SpaceBeforeFirstArg:
|
76
80
|
Enabled: false
|
77
81
|
|
78
82
|
Style/SpecialGlobalVars:
|
79
83
|
Exclude:
|
80
|
-
-
|
81
|
-
-
|
84
|
+
- Gemfile
|
85
|
+
- dry-initializer.gemspec
|
82
86
|
|
83
87
|
Style/StringLiterals:
|
84
88
|
EnforcedStyle: double_quotes
|
@@ -88,4 +92,4 @@ Style/StringLiteralsInInterpolation:
|
|
88
92
|
|
89
93
|
Style/TrivialAccessors:
|
90
94
|
Exclude:
|
91
|
-
-
|
95
|
+
- spec/**/*_spec.rb
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,75 @@
|
|
1
|
+
## v0.2.0 2016-04-28
|
2
|
+
|
3
|
+
The gem internals has been rewritten heavily to make the gem pluggable and fix
|
4
|
+
bugs in "container style". Type constraints were extracted to a plugin
|
5
|
+
that should be added explicitly.
|
6
|
+
|
7
|
+
Small extensions were added to type constraints to support constraint by any
|
8
|
+
object, and apply value coercion via `dry-types`.
|
9
|
+
|
10
|
+
Default assignments became slower (while plain type constraint are not)!
|
11
|
+
|
12
|
+
### Changed (backward-incompatible changes)
|
13
|
+
|
14
|
+
* Make dry-types constraint to coerce variables (@nepalez)
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# This will coerce `name: :foo` to `"foo"`
|
18
|
+
option :name, type: Dry::Types::Coercible::String
|
19
|
+
```
|
20
|
+
|
21
|
+
* Stop supporing proc type constraint (@nepalez)
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
option :name, type: ->(v) { String === v } # this does NOT work any more
|
25
|
+
```
|
26
|
+
|
27
|
+
later it will be implemented via coercion plugin (not added by default):
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'dry/initializer/coercion'
|
31
|
+
|
32
|
+
class MyClass
|
33
|
+
extend Dry::Initializer::Mixin
|
34
|
+
extend Dry::Initializer::Coercion
|
35
|
+
|
36
|
+
option :name, coercer: ->(v) { (String === v) ? v.to_sym : fail }
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
### Added
|
41
|
+
|
42
|
+
* Support type constraint via every object's case equality (@nepalez)
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
option :name, type: /foo/
|
46
|
+
option :name, type: (1..14)
|
47
|
+
```
|
48
|
+
|
49
|
+
* Support defaults and type constraints for the "container" syntax (@nepalez)
|
50
|
+
* Support adding extensions via plugin system (@nepalez)
|
51
|
+
|
52
|
+
### Internal
|
53
|
+
|
54
|
+
* Private method `##__after_initialize__` is added by the `Mixin` along with `#initialize` (@nepalez)
|
55
|
+
|
56
|
+
The previous implementation required defaults and types to be stored in the class method `.initializer_builder`.
|
57
|
+
That made "container" syntax to support neither defaults nor types.
|
58
|
+
|
59
|
+
Now the `#initializer` is still defined via `instance_eval(code)` for efficiency. Some operations
|
60
|
+
(like default assignments, coercions, dry-type constraints etc.) cannot be implemented in this way.
|
61
|
+
They are made inside `##__after_initialize__` callback, that is biult via `default_method(&block)`
|
62
|
+
using instance evals.
|
63
|
+
|
64
|
+
[Compare v0.1.1...v0.2.0](https://github.com/dry-rb/dry-initializer/compare/v0.1.1...v0.2.0)
|
65
|
+
|
1
66
|
## v0.1.1 2016-04-28
|
2
67
|
|
3
68
|
### Added
|
4
69
|
|
5
|
-
* `include Dry::Initializer.define -> do .. end` syntax (flash-gordon)
|
70
|
+
* `include Dry::Initializer.define -> do .. end` syntax (@flash-gordon)
|
71
|
+
|
72
|
+
[Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-initializer/compare/v0.1.0...v0.1.1)
|
6
73
|
|
7
74
|
## v0.1.0 2016-04-26
|
8
75
|
|
@@ -11,11 +78,13 @@ Backward compatibility is broken.
|
|
11
78
|
|
12
79
|
### Changed (backward-incompatible changes)
|
13
80
|
|
14
|
-
* Use `extend Dry::Initializer::Mixin` instead of `extend Dry::Initializer` (nepalez)
|
81
|
+
* Use `extend Dry::Initializer::Mixin` instead of `extend Dry::Initializer` (@nepalez)
|
15
82
|
|
16
83
|
### Added
|
17
84
|
|
18
|
-
* Use `include Dry::Initializer.define(&block)` as an alternative to extending the class (nepalez)
|
85
|
+
* Use `include Dry::Initializer.define(&block)` as an alternative to extending the class (@nepalez)
|
86
|
+
|
87
|
+
[Compare v0.0.1...v0.1.0](https://github.com/dry-rb/dry-initializer/compare/v0.0.1...v0.1.0)
|
19
88
|
|
20
89
|
## v0.0.1 2016-04-09
|
21
90
|
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2016 Andrew Kozin (
|
3
|
+
Copyright (c) 2016 Andrew Kozin (nepalez), Vladimir Kochnev (marshall-lee)
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -13,6 +13,9 @@
|
|
13
13
|
[codeclimate]: https://codeclimate.com/github/dry-rb/dry-initializer
|
14
14
|
[coveralls]: https://coveralls.io/r/dry-rb/dry-initializer
|
15
15
|
[inchpages]: http://inch-ci.org/github/dry-rb/dry-initializer
|
16
|
+
[docs]: http://dry-rb.org/gems/dry-initializer/
|
17
|
+
[benchmarks]: https://github.com/dry-rb/dry-initializer/wiki
|
18
|
+
[license]: http://opensource.org/licenses/MIT
|
16
19
|
|
17
20
|
DSL for building class initializer with params and options.
|
18
21
|
|
@@ -45,7 +48,7 @@ class User
|
|
45
48
|
extend Dry::Initializer::Mixin
|
46
49
|
|
47
50
|
# Params of the initializer along with corresponding readers
|
48
|
-
param :name
|
51
|
+
param :name
|
49
52
|
param :role, default: proc { 'customer' }
|
50
53
|
# Options of the initializer along with corresponding readers
|
51
54
|
option :admin, default: proc { false }
|
@@ -60,286 +63,11 @@ user.role # => 'admin'
|
|
60
63
|
user.admin # => true
|
61
64
|
```
|
62
65
|
|
63
|
-
|
64
|
-
|
65
|
-
```ruby
|
66
|
-
class User
|
67
|
-
attr_reader :name, :type, :admin
|
68
|
-
|
69
|
-
def initializer(name, type = 'customer', admin: false)
|
70
|
-
@name = name
|
71
|
-
@type = type
|
72
|
-
@admin = admin
|
73
|
-
|
74
|
-
fail TypeError unless String === @name
|
75
|
-
end
|
76
|
-
end
|
77
|
-
```
|
78
|
-
|
79
|
-
### Container Version
|
80
|
-
|
81
|
-
Instead of extending a class with the `Dry::Initializer::Mixin`, you can include a container with the initializer:
|
82
|
-
|
83
|
-
```ruby
|
84
|
-
require 'dry-initializer'
|
85
|
-
|
86
|
-
class User
|
87
|
-
# notice `-> do .. end` syntax
|
88
|
-
include Dry::Initializer.define -> do
|
89
|
-
param :name, type: String
|
90
|
-
param :role, default: proc { 'customer' }
|
91
|
-
option :admin, default: proc { false }
|
92
|
-
end
|
93
|
-
end
|
94
|
-
```
|
95
|
-
|
96
|
-
Now you do not pollute a class with new variables, but isolate them in a special "container" module with the initializer and attribute readers. This method should be preferred when you don't need subclassing.
|
97
|
-
|
98
|
-
If you still need the DSL (`param` and `option`) to be inherited, use the direct extension:
|
99
|
-
|
100
|
-
```ruby
|
101
|
-
require 'dry-initializer'
|
102
|
-
|
103
|
-
class BaseService
|
104
|
-
extend Dry::Initializer::Mixin
|
105
|
-
alias_method :dependency, :param
|
106
|
-
end
|
107
|
-
|
108
|
-
class ShowUser < BaseService
|
109
|
-
dependency :user
|
110
|
-
|
111
|
-
def call
|
112
|
-
puts user&.name
|
113
|
-
end
|
114
|
-
end
|
115
|
-
```
|
116
|
-
|
117
|
-
### Params and Options
|
118
|
-
|
119
|
-
Use `param` to define plain argument:
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
class User
|
123
|
-
extend Dry::Initializer::Mixin
|
124
|
-
|
125
|
-
param :name
|
126
|
-
param :email
|
127
|
-
end
|
128
|
-
|
129
|
-
user = User.new 'Andrew', 'andrew@email.com'
|
130
|
-
user.name # => 'Andrew'
|
131
|
-
user.email # => 'andrew@email.com'
|
132
|
-
```
|
133
|
-
|
134
|
-
Use `option` to define named (hash) argument:
|
135
|
-
|
136
|
-
```ruby
|
137
|
-
class User
|
138
|
-
extend Dry::Initializer::Mixin
|
139
|
-
|
140
|
-
option :name
|
141
|
-
option :email
|
142
|
-
end
|
143
|
-
|
144
|
-
user = User.new email: 'andrew@email.com', name: 'Andrew'
|
145
|
-
user.name # => 'Andrew'
|
146
|
-
user.email # => 'andrew@email.com'
|
147
|
-
```
|
148
|
-
|
149
|
-
All names should be unique:
|
150
|
-
|
151
|
-
```ruby
|
152
|
-
class User
|
153
|
-
extend Dry::Initializer::Mixin
|
154
|
-
|
155
|
-
param :name
|
156
|
-
option :name # => raises #<SyntaxError ...>
|
157
|
-
end
|
158
|
-
```
|
159
|
-
|
160
|
-
### Default Values
|
161
|
-
|
162
|
-
By default both params and options are mandatory. Use `:default` key to make them optional:
|
163
|
-
|
164
|
-
```ruby
|
165
|
-
class User
|
166
|
-
extend Dry::Initializer::Mixin
|
167
|
-
|
168
|
-
param :name, default: proc { 'Unknown user' }
|
169
|
-
option :email, default: proc { 'unknown@example.com' }
|
170
|
-
end
|
171
|
-
|
172
|
-
user = User.new
|
173
|
-
user.name # => 'Unknown user'
|
174
|
-
user.email # => 'unknown@example.com'
|
175
|
-
|
176
|
-
user = User.new 'Vladimir', email: 'vladimir@example.com'
|
177
|
-
user.name # => 'Vladimir'
|
178
|
-
user.email # => 'vladimir@example.com'
|
179
|
-
```
|
180
|
-
|
181
|
-
Set `nil` as a default value explicitly:
|
182
|
-
|
183
|
-
```ruby
|
184
|
-
class User
|
185
|
-
extend Dry::Initializer::Mixin
|
186
|
-
|
187
|
-
param :name
|
188
|
-
option :email, default: proc { nil }
|
189
|
-
end
|
190
|
-
|
191
|
-
user = User.new 'Andrew'
|
192
|
-
user.email # => nil
|
193
|
-
|
194
|
-
user = User.new
|
195
|
-
# => #<ArgumentError ...>
|
196
|
-
```
|
197
|
-
|
198
|
-
You **must** wrap default values into procs.
|
199
|
-
|
200
|
-
If you need to **assign** proc as a default value, wrap it to another one:
|
201
|
-
|
202
|
-
```ruby
|
203
|
-
class User
|
204
|
-
extend Dry::Initializer::Mixin
|
205
|
-
|
206
|
-
param :name_proc, default: proc { proc { 'Unknown user' } }
|
207
|
-
end
|
208
|
-
|
209
|
-
user = User.new
|
210
|
-
user.name_proc.call # => 'Unknown user'
|
211
|
-
```
|
212
|
-
|
213
|
-
Proc will be executed in a scope of new instance. You can refer to other arguments:
|
214
|
-
|
215
|
-
```ruby
|
216
|
-
class User
|
217
|
-
extend Dry::Initializer::Mixin
|
218
|
-
|
219
|
-
param :name
|
220
|
-
param :email, default: proc { "#{name.downcase}@example.com" }
|
221
|
-
end
|
222
|
-
|
223
|
-
user = User.new 'Andrew'
|
224
|
-
user.email # => 'andrew@example.com'
|
225
|
-
```
|
226
|
-
|
227
|
-
**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).
|
228
|
-
|
229
|
-
```ruby
|
230
|
-
class User
|
231
|
-
extend Dry::Initializer::Mixin
|
232
|
-
|
233
|
-
param :name, default: -> (obj) { 'Dude' }
|
234
|
-
end
|
235
|
-
```
|
236
|
-
|
237
|
-
[instance_eval]: http://ruby-doc.org/core-2.2.0/BasicObject.html#method-i-instance_eval
|
238
|
-
|
239
|
-
### Order of Declarations
|
240
|
-
|
241
|
-
You cannot define required parameter after optional ones. The following example raises `SyntaxError` exception:
|
242
|
-
|
243
|
-
```ruby
|
244
|
-
class User
|
245
|
-
extend Dry::Initializer::Mixin
|
246
|
-
|
247
|
-
param :name, default: proc { 'Unknown name' }
|
248
|
-
param :email # => #<SyntaxError ...>
|
249
|
-
end
|
250
|
-
```
|
251
|
-
|
252
|
-
### Type Constraints
|
253
|
-
|
254
|
-
To set type constraint use `:type` key:
|
255
|
-
|
256
|
-
```ruby
|
257
|
-
class User
|
258
|
-
extend Dry::Initializer::Mixin
|
259
|
-
|
260
|
-
param :name, type: String
|
261
|
-
end
|
262
|
-
|
263
|
-
user = User.new 'Andrew'
|
264
|
-
user.name # => 'Andrew'
|
265
|
-
|
266
|
-
user = User.new :andrew
|
267
|
-
# => #<TypeError ...>
|
268
|
-
```
|
269
|
-
|
270
|
-
You can use plain Ruby classes and modules as type constraint (see above), or use [dry-types][dry-types]:
|
271
|
-
|
272
|
-
```ruby
|
273
|
-
class User
|
274
|
-
extend Dry::Initializer::Mixin
|
275
|
-
|
276
|
-
param :name, type: Dry::Types::Coercion::String
|
277
|
-
end
|
278
|
-
```
|
279
|
-
|
280
|
-
Or you can define custom constraint as a proc:
|
281
|
-
|
282
|
-
```ruby
|
283
|
-
class User
|
284
|
-
extend Dry::Initializer::Mixin
|
285
|
-
|
286
|
-
param :name, type: proc { |v| raise TypeError if String === v }
|
287
|
-
end
|
288
|
-
|
289
|
-
user = User.new name: 'Andrew'
|
290
|
-
# => #<TypeError ...>
|
291
|
-
```
|
292
|
-
|
293
|
-
[dry-types]: https://github.com/dryrb/dry-types
|
294
|
-
|
295
|
-
### Reader
|
296
|
-
|
297
|
-
By default `attr_reader` is defined for every param and option.
|
298
|
-
|
299
|
-
To skip the reader, use `reader: false`:
|
300
|
-
|
301
|
-
```ruby
|
302
|
-
class User
|
303
|
-
extend Dry::Initializer::Mixin
|
304
|
-
|
305
|
-
param :name
|
306
|
-
param :email, reader: false
|
307
|
-
end
|
308
|
-
|
309
|
-
user = User.new 'Luke', 'luke@example.com'
|
310
|
-
user.name # => 'Luke'
|
311
|
-
|
312
|
-
user.email # => #<NoMethodError ...>
|
313
|
-
user.instance_variable_get :@email # => 'luke@example.com'
|
314
|
-
```
|
315
|
-
|
316
|
-
No writers are defined. Define them using pure ruby `attr_writer` when necessary.
|
317
|
-
|
318
|
-
### Subclassing
|
319
|
-
|
320
|
-
Subclassing preserves all definitions being made inside a superclass:
|
321
|
-
|
322
|
-
```ruby
|
323
|
-
class User
|
324
|
-
extend Dry::Initializer::Mixin
|
325
|
-
|
326
|
-
param :name
|
327
|
-
end
|
328
|
-
|
329
|
-
class Employee < User
|
330
|
-
param :position
|
331
|
-
end
|
332
|
-
|
333
|
-
employee = Employee.new('John', 'supercargo')
|
334
|
-
employee.name # => 'John'
|
335
|
-
employee.position # => 'supercargo'
|
336
|
-
```
|
66
|
+
See full documentation on the [Dry project official site][docs]
|
337
67
|
|
338
68
|
## Benchmarks
|
339
69
|
|
340
|
-
The `dry-initializer` is
|
341
|
-
|
342
|
-
[benchmarks]: https://github.com/dry-rb/dry-initializer/wiki
|
70
|
+
The `dry-initializer` is pretty fast for rubies 2.2+ [comparing to other libraries][benchmarks].
|
343
71
|
|
344
72
|
## Compatibility
|
345
73
|
|
@@ -356,5 +84,5 @@ Tested under rubies [compatible to MRI 2.2+](.travis.yml).
|
|
356
84
|
|
357
85
|
## License
|
358
86
|
|
359
|
-
The gem is available as open source under the terms of the [MIT License]
|
87
|
+
The gem is available as open source under the terms of the [MIT License][license].
|
360
88
|
|