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.
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