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