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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -9
  3. data/CHANGELOG.md +72 -3
  4. data/LICENSE.txt +1 -1
  5. data/README.md +7 -279
  6. data/benchmarks/with_types.rb +2 -0
  7. data/benchmarks/with_types_and_defaults.rb +2 -0
  8. data/dry-initializer.gemspec +1 -1
  9. data/lib/dry/initializer.rb +5 -4
  10. data/lib/dry/initializer/builder.rb +66 -13
  11. data/lib/dry/initializer/errors.rb +5 -7
  12. data/lib/dry/initializer/errors/default_value_error.rb +6 -0
  13. data/lib/dry/initializer/errors/order_error.rb +7 -0
  14. data/lib/dry/initializer/errors/plugin_error.rb +6 -0
  15. data/lib/dry/initializer/errors/{existing_argument_error.rb → redefinition_error.rb} +1 -1
  16. data/lib/dry/initializer/errors/type_constraint_error.rb +6 -0
  17. data/lib/dry/initializer/errors/type_error.rb +4 -3
  18. data/lib/dry/initializer/mixin.rb +7 -7
  19. data/lib/dry/initializer/plugins.rb +10 -0
  20. data/lib/dry/initializer/plugins/base.rb +42 -0
  21. data/lib/dry/initializer/plugins/default_proc.rb +28 -0
  22. data/lib/dry/initializer/plugins/signature.rb +35 -0
  23. data/lib/dry/initializer/plugins/type_constraint.rb +58 -0
  24. data/lib/dry/initializer/plugins/variable_setter.rb +12 -0
  25. data/lib/dry/initializer/signature.rb +47 -0
  26. data/spec/dry/container_spec.rb +3 -3
  27. data/spec/dry/dry_type_constraint_spec.rb +30 -0
  28. data/spec/dry/invalid_default_spec.rb +1 -1
  29. data/spec/dry/{proc_type_spec.rb → object_type_constraint_spec.rb} +4 -4
  30. data/spec/dry/{poro_type_spec.rb → plain_type_constraint_spec.rb} +1 -1
  31. data/spec/dry/value_coercion_via_dry_types_spec.rb +21 -0
  32. metadata +29 -25
  33. data/lib/dry/initializer/argument.rb +0 -96
  34. data/lib/dry/initializer/arguments.rb +0 -85
  35. data/lib/dry/initializer/errors/invalid_default_value_error.rb +0 -6
  36. data/lib/dry/initializer/errors/invalid_type_error.rb +0 -6
  37. data/lib/dry/initializer/errors/key_error.rb +0 -5
  38. data/lib/dry/initializer/errors/missed_default_value_error.rb +0 -5
  39. data/spec/dry/dry_type_spec.rb +0 -25
  40. data/spec/dry/invalid_type_spec.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f262a2ae5fa55ff9bc86dee062ec773868b4671
4
- data.tar.gz: a89671bbf85a6b4da055a639b7125a44456fe249
3
+ metadata.gz: a155e17b7e2f0fb9274bf3b6511c64380784ae90
4
+ data.tar.gz: 967ba81a147fa585ba889b3e97378a3340db312a
5
5
  SHA512:
6
- metadata.gz: 0d09cbdfa72b94010534ce22a4d252c8158267b94e46a88a0d588bed2070c0256701be42c701290b51eabdfbced55135012c216e7fecf9386caf3cbd5c1e2fa9
7
- data.tar.gz: a360f864906d84a652f62355082f6ad605ac569ef0d3c0db4a07203f3d34e359b5736b40279a9561a371221ce1dcdc47e063256d86e0e7760b5f607199b69d62
6
+ metadata.gz: af677c57dc5ca40e7c2d3540cb566e145643daecf2eb564c752f95b3123f74bfed8320edecf9764cb933cd007ee7421728e1965941f122187dcdbd7ff0b830bd
7
+ data.tar.gz: 7d8d21a38ff8a0cb08a41ee8e3c37665a020a1314bb59851f3c85d3eff58b96196a105c8a32c8f9b46bb8961f5c2681122c578fe6a01d481d270d02a2a956944
@@ -7,20 +7,20 @@ AllCops:
7
7
 
8
8
  Lint/HandleExceptions:
9
9
  Exclude:
10
- - '**/*_spec.rb'
10
+ - spec/**/*_spec.rb
11
11
 
12
12
  Lint/RescueException:
13
13
  Exclude:
14
- - '**/*_spec.rb'
14
+ - spec/**/*_spec.rb
15
15
 
16
16
  Metrics/LineLength:
17
17
  Max: 80
18
18
  Exclude:
19
- - 'spec/**/*.rb'
19
+ - spec/**/*_spec.rb
20
20
 
21
21
  Style/AccessorMethodName:
22
22
  Exclude:
23
- - '**/*_spec.rb'
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
- - '**/*_spec.rb'
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
- - '**/*_spec.rb'
77
+ - spec/**/*_spec.rb
74
78
 
75
79
  Style/SpaceBeforeFirstArg:
76
80
  Enabled: false
77
81
 
78
82
  Style/SpecialGlobalVars:
79
83
  Exclude:
80
- - '**/Gemfile'
81
- - '**/*.gemspec'
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
- - '**/*_spec.rb'
95
+ - spec/**/*_spec.rb
@@ -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
 
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016 Andrew Kozin (aka nepalez)
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, type: String
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
- This is pretty the same as:
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 a [fastest DSL][benchmarks] for rubies 2.2+ except for cases when core `Struct` is sufficient.
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](http://opensource.org/licenses/MIT).
87
+ The gem is available as open source under the terms of the [MIT License][license].
360
88