dry-initializer 3.0.1

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +23 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +4 -0
  5. data/.rubocop.yml +51 -0
  6. data/.travis.yml +28 -0
  7. data/CHANGELOG.md +883 -0
  8. data/Gemfile +29 -0
  9. data/Guardfile +5 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +90 -0
  12. data/Rakefile +8 -0
  13. data/benchmarks/compare_several_defaults.rb +82 -0
  14. data/benchmarks/plain_options.rb +63 -0
  15. data/benchmarks/plain_params.rb +84 -0
  16. data/benchmarks/with_coercion.rb +71 -0
  17. data/benchmarks/with_defaults.rb +66 -0
  18. data/benchmarks/with_defaults_and_coercion.rb +59 -0
  19. data/dry-initializer.gemspec +20 -0
  20. data/lib/dry-initializer.rb +1 -0
  21. data/lib/dry/initializer.rb +61 -0
  22. data/lib/dry/initializer/builders.rb +7 -0
  23. data/lib/dry/initializer/builders/attribute.rb +81 -0
  24. data/lib/dry/initializer/builders/initializer.rb +61 -0
  25. data/lib/dry/initializer/builders/reader.rb +50 -0
  26. data/lib/dry/initializer/builders/signature.rb +32 -0
  27. data/lib/dry/initializer/config.rb +184 -0
  28. data/lib/dry/initializer/definition.rb +65 -0
  29. data/lib/dry/initializer/dispatchers.rb +112 -0
  30. data/lib/dry/initializer/dispatchers/build_nested_type.rb +59 -0
  31. data/lib/dry/initializer/dispatchers/check_type.rb +43 -0
  32. data/lib/dry/initializer/dispatchers/prepare_default.rb +40 -0
  33. data/lib/dry/initializer/dispatchers/prepare_ivar.rb +12 -0
  34. data/lib/dry/initializer/dispatchers/prepare_optional.rb +13 -0
  35. data/lib/dry/initializer/dispatchers/prepare_reader.rb +30 -0
  36. data/lib/dry/initializer/dispatchers/prepare_source.rb +28 -0
  37. data/lib/dry/initializer/dispatchers/prepare_target.rb +44 -0
  38. data/lib/dry/initializer/dispatchers/unwrap_type.rb +22 -0
  39. data/lib/dry/initializer/dispatchers/wrap_type.rb +27 -0
  40. data/lib/dry/initializer/dsl.rb +43 -0
  41. data/lib/dry/initializer/mixin.rb +15 -0
  42. data/lib/dry/initializer/mixin/local.rb +19 -0
  43. data/lib/dry/initializer/mixin/root.rb +10 -0
  44. data/lib/dry/initializer/struct.rb +40 -0
  45. data/lib/dry/initializer/undefined.rb +2 -0
  46. data/lib/tasks/benchmark.rake +41 -0
  47. data/lib/tasks/profile.rake +78 -0
  48. data/spec/attributes_spec.rb +38 -0
  49. data/spec/coercion_of_nil_spec.rb +25 -0
  50. data/spec/custom_dispatchers_spec.rb +35 -0
  51. data/spec/custom_initializer_spec.rb +30 -0
  52. data/spec/default_values_spec.rb +83 -0
  53. data/spec/definition_spec.rb +111 -0
  54. data/spec/invalid_default_spec.rb +13 -0
  55. data/spec/list_type_spec.rb +32 -0
  56. data/spec/missed_default_spec.rb +14 -0
  57. data/spec/nested_type_spec.rb +44 -0
  58. data/spec/optional_spec.rb +71 -0
  59. data/spec/options_tolerance_spec.rb +11 -0
  60. data/spec/public_attributes_utility_spec.rb +22 -0
  61. data/spec/reader_spec.rb +87 -0
  62. data/spec/repetitive_definitions_spec.rb +69 -0
  63. data/spec/several_assignments_spec.rb +41 -0
  64. data/spec/spec_helper.rb +22 -0
  65. data/spec/subclassing_spec.rb +49 -0
  66. data/spec/type_argument_spec.rb +35 -0
  67. data/spec/type_constraint_spec.rb +78 -0
  68. data/spec/value_coercion_via_dry_types_spec.rb +29 -0
  69. metadata +189 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e17a987f9500b55fd7bf3c60caa5e8ce5c4c26cb78b94f339b62a63bdeb5a9e3
4
+ data.tar.gz: 362138efc7974312bf747f060c7af4d4117e6b8c7648849998c1aefb39d14b1e
5
+ SHA512:
6
+ metadata.gz: fc4416e43fce6418f4708f5d7fc6753096009e9f2087f334bc11a2edeb44b3f9099d6d53ad9969d7e38ffefa524031c0e95fd4c7cb277ff7fed1a9ff63ebad5b
7
+ data.tar.gz: a2745ea32279c9e6bd9a964b0cef5e876bf3f02afd604b4193e6223d629fc1ca6ee8fd22cf1543d652b9ff5548b3bb9a7fc28c7a06f4eeb04cf233b4ccf451de
@@ -0,0 +1,23 @@
1
+ ---
2
+ engines:
3
+ rubocop:
4
+ enabled: true
5
+ checks:
6
+ Rubocop/Style/FrozenStringLiteralComment:
7
+ enabled: false
8
+ Rubocop/Style/PercentLiteralDelimiters:
9
+ enabled: false
10
+ Rubocop/Lint/UnderscorePrefixedVariableName:
11
+ enabled: false
12
+ duplication:
13
+ enabled: true
14
+ config:
15
+ languages:
16
+ - ruby
17
+ exclude_paths:
18
+ - "benchmarks/**/*"
19
+ - "spec/**/*"
20
+ - "lib/tasks/**/*"
21
+ ratings:
22
+ paths:
23
+ - "lib/**/*"
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /*.gem
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
4
+ --warnings
@@ -0,0 +1,51 @@
1
+ ---
2
+ AllCops:
3
+ DisplayCopNames: true
4
+ DisplayStyleGuide: true
5
+ StyleGuideCopsOnly: true
6
+ TargetRubyVersion: 2.3
7
+ Exclude:
8
+ - lib/tasks/*.rake
9
+
10
+ Bundler/DuplicatedGem:
11
+ Enabled: false
12
+
13
+ Naming/FileName:
14
+ Exclude:
15
+ - lib/dry-initializer.rb
16
+
17
+ Style/CaseEquality:
18
+ Enabled: false
19
+
20
+ Style/ClassAndModuleChildren:
21
+ Enabled: false
22
+
23
+ Style/ClassVars:
24
+ Enabled: false
25
+
26
+ Style/Documentation:
27
+ Enabled: false
28
+
29
+ Style/DoubleNegation:
30
+ Enabled: false
31
+
32
+ Style/Lambda:
33
+ Exclude:
34
+ - spec/**/*.rb
35
+
36
+ Style/LambdaCall:
37
+ Enabled: false
38
+
39
+ Style/RescueModifier:
40
+ Exclude:
41
+ - spec/**/*.rb
42
+
43
+ Style/Semicolon:
44
+ Exclude:
45
+ - spec/**/*.rb
46
+
47
+ Style/StringLiterals:
48
+ EnforcedStyle: double_quotes
49
+
50
+ Style/StringLiteralsInInterpolation:
51
+ EnforcedStyle: double_quotes
@@ -0,0 +1,28 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ bundler_args: --without benchmarks tools
5
+ script:
6
+ - bundle exec rake spec
7
+ rvm:
8
+ - 2.3.8
9
+ - 2.4.6
10
+ - 2.5.5
11
+ - 2.6.2
12
+ - jruby-9.2.7.0
13
+ - jruby-9000
14
+ - rbx-3
15
+ - ruby-head
16
+ - truffleruby
17
+ env:
18
+ global:
19
+ - JRUBY_OPTS='--dev -J-Xmx1024M'
20
+ matrix:
21
+ allow_failures:
22
+ - rvm: rbx-3
23
+ - rvm: ruby-head
24
+ - rvm: jruby-head
25
+ - rvm: truffleruby
26
+ include:
27
+ - rvm: jruby-head
28
+ before_install: gem install bundler --no-document
@@ -0,0 +1,883 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
+ and this project adheres to [Semantic Versioning](http://semver.org/).
7
+
8
+ ## [3.0.1] [2019-04-15]
9
+
10
+ ### Fixed
11
+
12
+ - Usage of underscored names of `option`-s and `param`-s (nepalez)
13
+
14
+ You can use any sequence of underscores except for in nested types.
15
+ In nested types single underscores can be used to split alphanumeric
16
+ parts only.
17
+
18
+ ```ruby
19
+ class Test
20
+ extend Dry::Initializer
21
+
22
+ # Proper usage
23
+ option :foo_bar do
24
+ option :__foo__, proc(&:to_s)
25
+ end
26
+ end
27
+
28
+ # Improper usage
29
+ option :__foo__ do
30
+ # ...
31
+ end
32
+
33
+ option :foo__bar do
34
+ # ...
35
+ end
36
+ end
37
+ ```
38
+
39
+ This restriction is necessary because we constantize option/param names
40
+ when defining nested structs.
41
+
42
+ ## [3.0.0] [2019-04-14]
43
+
44
+ ### Added
45
+
46
+ - Support of wrapped types/coercers (nepalez)
47
+
48
+ ```ruby
49
+ class Test
50
+ # Wrap type to the array
51
+ param :foo, [proc(&:to_s)]
52
+ end
53
+
54
+ # And the value will be wrapped as well
55
+ test = Test.new(42)
56
+ test.foo # => ["42"]
57
+ ```
58
+
59
+ - It works with several layers of nesting (nepalez)
60
+
61
+ ```ruby
62
+ class Test
63
+ # Wrap type to the array
64
+ param :foo, [[proc(&:to_s)]]
65
+ end
66
+
67
+ # And the value will be wrapped as well
68
+ test = Test.new(42)
69
+ test.foo # => [["42"]]
70
+ ```
71
+
72
+ - Support of nested types/coercers (nepalez)
73
+
74
+ ```ruby
75
+ class Test
76
+ param :foo do
77
+ option :bar do
78
+ option :baz, proc(&:to_s)
79
+ end
80
+ end
81
+ end
82
+
83
+ test = Test.new(bar: { "baz" => 42 })
84
+ test.foo.bar.baz # => "42"
85
+ ```
86
+
87
+ - Wrapped/nested combinations are supported as well (nepalez)
88
+
89
+ ```ruby
90
+ class Test
91
+ param :foo, [] do
92
+ option :bar, proc(&:to_s)
93
+ end
94
+ end
95
+
96
+ test = Test.new(bar: 42)
97
+ test.foo.first.bar # => "42"
98
+ ```
99
+
100
+ ## [2.7.0] Unreleazed
101
+
102
+ ### Fixed
103
+
104
+ - Roll back master to the state of [2.5.0].
105
+
106
+ Somehow distinction between `@default_null` and `@null` variables
107
+ in the `Dry::Initializer::Builders` broken the `rom` library.
108
+
109
+ The version [2.6.0] has been yanked on rubygems, so the master
110
+ was rolled back to the previous state until the reason for
111
+ the incompatibility become clear (bjeanes, nepalez)
112
+
113
+ ## [2.6.0] [2018-09-09] (YANKED)
114
+
115
+ ## [2.5.0] [2018-08-17]
116
+
117
+ ### Fixed
118
+
119
+ - `nil` coercion (belousovAV)
120
+
121
+ When default value is `nil` instead of `Dry::Initializer::UNDEFINED`,
122
+ the coercion should be applied to any value, including `nil`, because
123
+ we cannot distinct "undefined" `nil` from the "assigned" `nil` value.
124
+
125
+ ## [2.4.0] [2018-02-01]
126
+
127
+ ### Added
128
+ - Dispatchers for adding syntax sugar to `param` and `options` (nepalez)
129
+
130
+ ```ruby
131
+ # Converts `integer: true` to `type: proc(&:to_i)`
132
+ dispatcher = ->(op) { op[:integer] ? op.merge(type: proc(&:to_i)) : op }
133
+ # Register a dispatcher
134
+ Dry::Initializer::Dispatchers << dispatcher
135
+ # Use syntax sugar
136
+ class User
137
+ param :id, integer: true # same as param :id, proc(&:to_i)
138
+ end
139
+ ```
140
+
141
+ ## [2.3.0] [2017-09-19]
142
+
143
+ ### Added
144
+ - Type coercer can take second argument for the initialized instance (nepalez)
145
+ This allows to wrap assigned value to the object that refers back
146
+ to the initializer instance. More verbose example:
147
+
148
+ ```ruby
149
+ class Location < String
150
+ attr_reader :parameter # refers back to its parameter
151
+
152
+ def initialize(name, parameter)
153
+ super(name)
154
+ @parameter = parameter
155
+ end
156
+ end
157
+
158
+ class Parameter
159
+ extend Dry::Initializer
160
+ param :name
161
+ param :location, ->(value, param) { Location.new(value, param) }
162
+ end
163
+
164
+ offset = Parameter.new "offset", location: "query"
165
+ offset.name # => "offset"
166
+ offset.location # => "query"
167
+ offset.location.parameter == offset # true
168
+ ```
169
+
170
+ ## [2.2.0] [2017-09-13]
171
+
172
+ ### Added
173
+ - Option `:desc` for option/param to add a description (nepalez)
174
+
175
+ - Methods `Definition#inch` and `Config#inch` to inspect definitions (nepalez)
176
+
177
+ ```ruby
178
+ class User
179
+ extend Dry::Initializer
180
+ option :name, proc(&:to_s), optional: true, desc: "User name"
181
+ option :email, optional: true, desc: "user email"
182
+ end
183
+
184
+ User.dry_initializer.inch
185
+ # @!method initialize(*, **options)
186
+ # Initializes an instance of User
187
+ # @option [Object] :name (optional) User name
188
+ # @option [Object] :email (optional) User email
189
+ # @return [User]
190
+ ```
191
+
192
+ ## [2.1.0] [2017-09-11]
193
+
194
+ ### Added
195
+ - Method `#options` to param/option definition (nepalez)
196
+
197
+ ```ruby
198
+ class User
199
+ extend Dry::Initializer
200
+ option :name, proc(&:to_s), optional: true
201
+ option :email, optional: true
202
+ end
203
+
204
+ User.dry_initializer.options.map do |option|
205
+ [option.source, option.options]
206
+ end
207
+ # => [
208
+ # [:name, { type: proc(&:to_s), as: :name, optional: true }],
209
+ # [:email, { as: :email, optional: true }]
210
+ # ]
211
+ ```
212
+
213
+ This method can be helpful for replicating params/options
214
+ in another class without inheritance.
215
+
216
+ ## [2.0.0] [2017-08-28]
217
+
218
+ The gem has been rewritten under the hood keeping its documented
219
+ interface about the same (see "Deleted" section below for the only
220
+ backward-incompatible change).
221
+
222
+ The main achievement of this version is fixing an edge case where
223
+ change in params/options of superclass wasn't reflected in its
224
+ previously declared subclasses.
225
+
226
+ Thanks to @solnic for the idea of class-level container,
227
+ and to @gzigzigzeo for persuading me to do this refactoring.
228
+
229
+ ### Deleted
230
+ - Undocumented variable `@__option__` which was the main reason for refactoring
231
+ (gzigzigzeo, nepalez).
232
+
233
+ ### Added
234
+ - Class method `.dry_initializer` -- a container for `.params` and `.options`
235
+ `.definitions` along with the `.null` setting (either `nil` or `UNDEFINED`)
236
+ used for unassigned values (nepalez)
237
+
238
+ - `.dry_initializer.attributes` method takes an instance of the same class
239
+ and returns the hash of assigned options. This provide the same
240
+ functionality as previously used instance variable `@__options__` (nepalez)
241
+
242
+ ```ruby
243
+ object.class.dry_initializer.attributes(object)
244
+ ```
245
+
246
+ When you use "Dry::Initializer.define -> { ... }" syntax,
247
+ the class method `.dry_initializer` is not defined. To access attributes
248
+ you should use private instance method `#__dry_initializer_config__` instead:
249
+
250
+ ```ruby
251
+ object.send(:__dry_initializer_config__).attributes(object)
252
+ ```
253
+
254
+ Both methods `.dry_initializer` and `#__dry_initializer_config__` refer
255
+ to the same object.
256
+
257
+ - `.dry_initializer.public_attributes`. This method works differently:
258
+ it looks through (possibly reloaded) readers instead of variables
259
+ (gzigzigzeo, nepalez)
260
+
261
+ ```ruby
262
+ object.class.dry_initializer.public_attributes(object)
263
+ ```
264
+
265
+ You can use the same trick as above mutatis mutandis.
266
+
267
+ ### Fixed
268
+ - Definition order dependency bug (nepalez)
269
+
270
+ I've found out that if you provided a subclass and then changed params
271
+ or options of its superclass, these changes woudn't be reflected in
272
+ subclasses until you change any of it params/options as well.
273
+
274
+ Now this bug is fixed: every time you call `param` or `option` at
275
+ any class, the gem scans through all its descendants to the very bottom
276
+ of the tree, and reloads their defintitions.
277
+
278
+ Being done in load time, the rebuilt makes no effect on runtime performance.
279
+
280
+ - Possible misbehavior when you define param and option with the same name (nepalez)
281
+
282
+ Doing this will provide `option :name` only, not both:
283
+
284
+ ```ruby
285
+ param :name
286
+ option :name
287
+ ```
288
+
289
+ - Attempt to redefine param/option of superclass with option/param in
290
+ its subclass will cause an exception because it would break
291
+ Liskov substitute principle with unexpected behaviour (nepalez)
292
+
293
+ No, you can do neither these definitions, nor vice versa:
294
+
295
+ ```ruby
296
+ class Foo
297
+ extend Dry::Intitializer
298
+ param :name
299
+ end
300
+
301
+ class Bar < Foo
302
+ option :name
303
+ end
304
+ ```
305
+
306
+ - When you reloading previously defined param of superclass, the gem
307
+ will check all its descendands for whether all required positional params
308
+ goes before optional ones (nepalez)
309
+
310
+ ```ruby
311
+ class Foo
312
+ param :name
313
+ # Foo: def initializer(name)
314
+ end
315
+
316
+ class Bar
317
+ param :email
318
+ # Bar: def initializer(name, email)
319
+ end
320
+
321
+ class Foo
322
+ # This raises SyntaxError because in Bar this would cause wrong definition
323
+ # Foo: def initializer(name = nil)
324
+ # Bar: def initializer(name = nil, email)
325
+ param :name, optional: true
326
+ end
327
+ ```
328
+
329
+ ### Changed
330
+ - Under the hood I've separated param/option settings declaration (a container
331
+ with param/option settings) from code builders for initializer and readers
332
+ (nepalez)
333
+
334
+ You can check both the code for the `__initializer__`:
335
+
336
+ ```ruby
337
+ class Foo
338
+ extend Dry::Initializer
339
+ # ...
340
+ end
341
+
342
+ Foo.dry_initializer.code
343
+ ```
344
+
345
+ and readers:
346
+
347
+ ```ruby
348
+ Foo.dry_initializer.params.map(&:code)
349
+ Foo.dry_initializer.options.map(&:code)
350
+
351
+ # or
352
+
353
+ Foo.dry_initializer.definitions.values.map(&:code)
354
+ ```
355
+
356
+ You can also check settings for every param and option using methods
357
+ `dry_initializer.params`, `dry_initializer.options` (lists), or
358
+ `dry_initializer.definitions` (hash).
359
+
360
+ You can check null value via `.dry_initializer.null` which is different
361
+ for `Dry::Initializer` and `Dry::Initializer[undefined: false]` modules.
362
+
363
+ - Optimized the code for `__initializer__`-s (the method where all magics occurs)
364
+ (nepalez)
365
+
366
+ Benchmarks remained about the same:
367
+
368
+ ```shell
369
+ rake benchmark
370
+ ```
371
+
372
+ ```
373
+ Benchmark for instantiation with plain params
374
+ value_struct: 4317196.9 i/s
375
+ plain Ruby: 4129803.9 i/s - 1.05x slower
376
+ dry-initializer: 1710702.1 i/s - 2.52x slower
377
+ concord: 1372630.4 i/s - 3.15x slower
378
+ values: 601651.8 i/s - 7.18x slower
379
+ attr_extras: 535599.5 i/s - 8.06x slower
380
+ ```
381
+
382
+ ```
383
+ Benchmark for instantiation with plain options
384
+ plain Ruby: 1769174.1 i/s
385
+ dry-initializer: 636634.1 i/s - 2.78x slower
386
+ kwattr: 423296.5 i/s - 4.18x slower
387
+ anima: 399415.0 i/s - 4.43x slower
388
+ ```
389
+
390
+ ```
391
+ Benchmark for instantiation with coercion
392
+ plain Ruby: 1565501.0 i/s
393
+ fast_attributes: 569952.9 i/s - 2.75x slower
394
+ dry-initializer: 461122.1 i/s - 3.39x slower
395
+ virtus: 138074.8 i/s - 11.34x slower
396
+ ```
397
+
398
+ ```
399
+ Benchmark for instantiation with default values
400
+ plain Ruby: 3402455.4 i/s
401
+ kwattr: 586206.5 i/s - 5.80x slower
402
+ dry-initializer: 528482.2 i/s - 6.44x slower
403
+ active_attr: 298697.7 i/s - 11.39x slower
404
+ ```
405
+
406
+ ```
407
+ Benchmark for instantiation with type constraints and default values
408
+ plain Ruby: 2881696.1 i/s
409
+ dry-initializer: 470815.1 i/s - 6.12x slower
410
+ virtus: 180272.6 i/s - 15.99x slower
411
+ ```
412
+
413
+ ## [1.4.1] [2017-04-05]
414
+
415
+ ### Fixed
416
+ - Warning about redefined `#initialize` in case the method reloaded in a klass
417
+ that extends the module (nepalez, sergey-chechaev)
418
+
419
+ ### Changed
420
+ - Rename `Dry::Initializer::DSL` -> `Dry::Initializer::ClassDSL` (nepalez)
421
+ - Add `Dry::Initializer::InstanceDSL` (nepalez)
422
+
423
+ ### Deprecated
424
+ - `Dry::Initializer::Mixin`. In latest version this was an alias for
425
+ `Dry::Initializer` that kept for backward compatibility for early versions of the gem.
426
+
427
+ This story will come to the end in `v2.1.0`.
428
+
429
+ ## [1.4.0] [2017-03-08]
430
+
431
+ ### Changed (backward-incompatible)
432
+ - The `@__options__` hash now collects all assigned attributes,
433
+ collected via `#option` (as before), and `#param` (nepalez)
434
+
435
+ ## [1.3.0] [2017-03-05]
436
+
437
+ ### Added
438
+ - No-undefined configuration of the initializer (nepalez, flash-gordon)
439
+
440
+ You can either extend or include module `Dry::Initializer` with additional option
441
+ `[undefined: false]`. This time `nil` will be assigned instead of
442
+ `Dry::Initializer::UNDEFINED`. Readers becomes faster because there is no need
443
+ to chech whether a variable was defined or not. At the same time the initializer
444
+ doesn't distinct cases when a variable was set to `nil` explicitly, and when it wasn's set at all:
445
+
446
+ class Foo # old behavior
447
+ extend Dry::Initializer
448
+ param :qux, optional: true
449
+ end
450
+
451
+ class Bar # new behavior
452
+ extend Dry::Initializer[undefined: false]
453
+ param :qux, optional: true
454
+ end
455
+
456
+ Foo.new.instance_variable_get(:@qux) # => Dry::Initializer::UNDEFINED
457
+ Bar.new.instance_variable_get(:@qux) # => nil
458
+
459
+ ### Changed
460
+ - Fixed method definitions for performance at the load time (nepalez, flash-gordon)
461
+
462
+ ## [1.2.0] [2017-03-05]
463
+
464
+ ### Fixed
465
+ - The `@__options__` variable collects renamed options after default values and coercions were applied (nepalez)
466
+
467
+ ## [1.1.3] [2017-03-01]
468
+
469
+ ### Added
470
+ - Support for lambdas as default values (nepalez, gzigzigzeo)
471
+
472
+ ## [1.1.2] [2017-02-06]
473
+
474
+ ### Changed
475
+ - Remove previously defined methods before redefining them (flash-gordon)
476
+
477
+ ## [1.1.1] [2017-02-04]
478
+
479
+ ### Fixed
480
+ - `@__options__` collects defined options only (nepalez)
481
+
482
+ ## [1.1.0] [2017-01-28]
483
+
484
+ ### Added
485
+ - enhancement via `Dry::Initializer::Attribute.dispatchers` registry (nepalez)
486
+
487
+ ```ruby
488
+ # Register dispatcher for `:string` option
489
+ Dry::Initializer::Attribute.dispatchers << ->(string: nil, **op) do
490
+ string ? op.merge(type: proc(&:to_s)) : op
491
+ end
492
+
493
+ # Now you can use the `:string` key for `param` and `option`
494
+ class User
495
+ extend Dry::Initializer
496
+ param :name, string: true
497
+ end
498
+
499
+ User.new(:Andy).name # => "Andy"
500
+ ```
501
+
502
+ ### Changed
503
+ - optimize assignments for performance (nepalez)
504
+
505
+ ## [1.0.0] [2017-01-22]
506
+
507
+ In this version the code has been rewritten for simplicity
508
+
509
+ ### Changed
510
+ - [BREAKING] when `param` or `option` was not defined, the corresponding **variable** is set to `Dry::Initializer::UNDEFINED`, but the **reader** (when defined) will return `nil` (nepalez)
511
+
512
+ - `Dry::Initializer` and `Dry::Initializer::Mixin` became aliases (nepalez)
513
+
514
+ ### Added
515
+ - support for reloading `param` and `option` definitions (nepalez)
516
+
517
+ class User
518
+ extend Dry::Initializer
519
+ param :name
520
+ param :phone, optional: true
521
+ end
522
+
523
+ User.new # => Boom!
524
+
525
+ class Admin < User
526
+ param :name, default: proc { 'Merlin' }
527
+ end
528
+
529
+ # order of the param not changed
530
+ Admin.new.name # => "Merlin"
531
+
532
+ - support for assignment of attributes via several options (nepalez)
533
+
534
+ class User
535
+ extend Dry::Initializer
536
+ option :phone
537
+ option :number, as: :phone
538
+ end
539
+
540
+ # Both ways provide the same result
541
+ User.new(phone: '1234567890').phone # => '1234567890'
542
+ User.new(number: '1234567890').phone # => '1234567890'
543
+
544
+ ## [0.11.0] [2017-01-02]
545
+
546
+ ### Added
547
+ - Support of reloading `#initializer` with `super` (nepalez)
548
+
549
+ ### Internal
550
+ - Refactor the way [#initializer] method is (re)defined (nepalez)
551
+
552
+ When you extend class with `Dry::Initializer::Mixin`, the initializer is
553
+ defined not "inside" the class per se, but inside the included module. The
554
+ reference to that module is stored as class-level `__initializer_mixin__`.
555
+
556
+ Mixin method [#initialize] calls another private method [#__initialize__].
557
+ It is this method to be reloaded every time you envoke a helper
558
+ `option` or `product`.
559
+
560
+ When new subclass is inherited, new mixin is added to chain of accessors,
561
+ but this time it does reload `__initialize__` only, not the `initialize`.
562
+ That is how you can safely reload initializer using `super`, but at the same
563
+ time use the whole power of dry-initializer DSL both in parent class and its
564
+ subclasses.
565
+
566
+ The whole stack of accessors looks like the following:
567
+ - Parent class mixin: `initialize` --> `__initialize__`
568
+ ^
569
+ - Parent class: `initialize`
570
+ - Subclass mixin: ^ `__initialize__`
571
+ - Subclass: `initialize`
572
+
573
+ See specification `spec/custom_initializer_spec.rb` to see how this works.
574
+
575
+ ## [0.10.2] [2016-12-31]
576
+
577
+ ### Added
578
+ - Support of Ruby 2.4 (flas-gordon)
579
+
580
+ ### Internal
581
+ - Code clearance for ROM integration (flash-gordon)
582
+
583
+ ## [0.10.1] [2016-12-27]
584
+
585
+ ### Fixed
586
+ - Wrong arity when there were no options and the last param had a default (nolith)
587
+
588
+ ## [0.10.0] [2016-11-20]
589
+
590
+ ### Deleted (BREAKING CHANGE!)
591
+ - Deprecated method DSL#using (nepalez)
592
+
593
+ ## [0.9.3] [2016-11-20]
594
+
595
+ ### Deprecated
596
+ - After discussion in [PR #17]: https://github.com/dry-rb/dry-initializer/pull/17)
597
+ (many thanks to @sahal2080 and @hrom512 for starting that issue and PR),
598
+ the method `using` is deprecated and will be removed from v0.10.0 (nepalez)
599
+
600
+ ### Fixed
601
+ - Support of weird option names (nepalez)
602
+
603
+ ```ruby
604
+ option :"First name", as: :first_name
605
+ ```
606
+
607
+ ## [0.9.2] [2016-11-10]
608
+
609
+ ### Fixed
610
+ - Validation of attributes (params and options) (nepalez)
611
+
612
+ ## [0.9.1] [2016-11-06]
613
+
614
+ ### Added
615
+ - Support for renaming an option during initialization (nepalez)
616
+
617
+ option :name, as: :username # to take :name option and create :username attribute
618
+
619
+ ## [0.9.0] [2016-11-06]
620
+
621
+ ### Added
622
+ - The method `#initialize` is defined when a class extended the module (nepalez)
623
+
624
+ In previous versions the method was defined only by `param` and `option` calls.
625
+
626
+ ### Breaking Changes
627
+ - The initializer accepts any option (but skips unknown) from the very beginning (nepalez)
628
+
629
+ ### Deleted
630
+ - Deprecated methods `tolerant_to_unknown_options` and `intolerant_to_unknown_options` (nepalez)
631
+
632
+ ### Internal
633
+ - Refactor scope (`using`) to support methods renaming and aliasing (nepalez)
634
+
635
+ ## [0.8.1] [2016-11-05]
636
+
637
+ ### Added
638
+ - Support for `dry-struct`ish syntax for constraints (type as a second parameter) (nepalez)
639
+
640
+ option :name, Dry::Types['strict.string']
641
+
642
+ ## [0.8.0] [2016-11-05]
643
+
644
+ In this version we switched from key arguments to ** to support special keys:
645
+
646
+ option :end
647
+ option :begin
648
+
649
+ In previous versions this was translated to
650
+
651
+ def initialize(end:, begin:)
652
+ @end = end # BOOM! SyntaxError!
653
+ @begin = begin # Potential BOOM (unreached)
654
+ end
655
+
656
+ Now the assignment is imlemented like this:
657
+
658
+ def initialize(**__options__)
659
+ @end = __options__.fetch(:end)
660
+ @begin = __options__.fetch(:begin)
661
+ end
662
+
663
+ As a side effect of the change the initializer becomes tolerant
664
+ to any unknown option if, and only if some `option` was set explicitly.
665
+
666
+ Methods `tolerant_to_unknown_options` and `intolerant_to_unknown_options`
667
+ are deprecated and will be removed in the next version of the gem.
668
+
669
+ ### Added
670
+ - support for special options like `option :end`, `option :begin` etc. (nepalez)
671
+
672
+ ### Changed
673
+ - switched from key arguments to serialized hash argument in the initializer (nepalez)
674
+
675
+ ### Breaking Changes
676
+ - the initializer becomes tolerant to unknown options when any `option` was set,
677
+ ignoring `intolerant_to_unknown_options` helper.
678
+
679
+ - the initializer becomes intolerant to options when no `option` was set,
680
+ ignoring `tolerant_to_unknown_options` helper.
681
+
682
+ ### Deprecated
683
+ - `tolerant_to_unknown_options`
684
+ - `intolerant_to_unknown_options`
685
+
686
+ ## [0.7.0] [2016-10-11]
687
+
688
+ ### Added
689
+ - Shared settings with `#using` method (nepalez)
690
+
691
+ ## [0.6.0] [2016-10-09]
692
+
693
+ ### Added
694
+ - Support for private and protected readers in the `reader:` option (jmgarnier)
695
+
696
+ ## [0.5.0] [2016-08-21]
697
+
698
+ ### Added
699
+ - Allow `optional` attribute to be left undefined (nepalez)
700
+
701
+ ## [0.4.0] [2016-05-28]
702
+
703
+ ### Deleted (backward-incompatible changes)
704
+ - Support of modules and case equality as type constraints (nepalez)
705
+
706
+ ## [0.3.3] [2016-05-28]
707
+
708
+ - Add deprecation warnings about modules and case equality as type constraints (nepalez)
709
+
710
+ ## [0.3.2] [2016-05-25]
711
+
712
+ ### Fixed
713
+ - Add explicit requirement for ruby 'set' (rickenharp)
714
+
715
+ ## [0.3.1] [2016-05-22]
716
+
717
+ ### Added
718
+ - Support for tolerance to unknown options (nepalez)
719
+
720
+ ## [0.3.0] [2016-05-19]
721
+
722
+ Breaks interface for adding new plugins. Register new plugin via:
723
+
724
+ ```
725
+ def self.extended(klass)
726
+ klass.register_initializer_plugin NewPlugin
727
+ end
728
+ ```
729
+
730
+ instead of:
731
+
732
+ ```
733
+ def self.extended(klass)
734
+ klass.initializer_builder.register NewPlugin
735
+ end
736
+ ```
737
+
738
+ While the private method ##initializer_builder is still accessible
739
+ its method #register doesn't mutate the builder instance.
740
+
741
+ ### Changed (backward-incompatible changes)
742
+ - Made Mixin##initializer_builder method private (nepalez)
743
+ - Add Mixin#register_initializer_plugin(plugin) method (nepalez)
744
+
745
+ ### Fixed
746
+ - Prevent plugin's registry from polluting superclass (nepalez)
747
+
748
+ ### Changed
749
+ - Make all instances (Builder and Signature) immutable (nepalez)
750
+ - Decouple mixin from a builder to prevent pollution (nepalez)
751
+ - Ensure default value block can use private variables (jeremyf)
752
+
753
+ ## [0.2.1] [2016-05-19]
754
+
755
+ ### Fixed
756
+ - Fix polluting superclass with declarations from subclass (nepalez)
757
+
758
+ ### Changed
759
+ - Make all instances (Builder and Signature) immutable (nepalez)
760
+ - Decouple mixin from a builder to prevent pollution (nepalez)
761
+ - Ensure default value block can use private variables (jeremyf)
762
+
763
+ ## [0.2.0] [2016-05-16]
764
+
765
+ The gem internals has been rewritten heavily to make the gem pluggable and fix
766
+ bugs in "container style". Type constraints were extracted to a plugin
767
+ that should be added explicitly.
768
+
769
+ Small extensions were added to type constraints to support constraint by any
770
+ object, and apply value coercion via `dry-types`.
771
+
772
+ Default assignments became slower (while plain type constraint are not)!
773
+
774
+ ### Changed (backward-incompatible changes)
775
+ - Make dry-types constraint to coerce variables (nepalez)
776
+
777
+ ```ruby
778
+ # This will coerce `name: :foo` to `"foo"`
779
+ option :name, type: Dry::Types::Coercible::String
780
+ ```
781
+
782
+ - Stop supporing proc type constraint (nepalez)
783
+
784
+ ```ruby
785
+ option :name, type: ->(v) { String === v } # this does NOT work any more
786
+ ```
787
+
788
+ later it will be implemented via coercion plugin (not added by default):
789
+
790
+ ```ruby
791
+ require 'dry/initializer/coercion'
792
+
793
+ class MyClass
794
+ extend Dry::Initializer::Mixin
795
+ extend Dry::Initializer::Coercion
796
+
797
+ option :name, coercer: ->(v) { (String === v) ? v.to_sym : fail }
798
+ end
799
+ ```
800
+
801
+ ### Added
802
+ - Support type constraint via every object's case equality (nepalez)
803
+
804
+ ```ruby
805
+ option :name, type: /foo/
806
+ option :name, type: (1...14)
807
+ ```
808
+
809
+ - Support defaults and type constraints for the "container" syntax (nepalez)
810
+ - Support adding extensions via plugin system (nepalez)
811
+
812
+ ### Internal
813
+ - Private method `##__after_initialize__` is added by the `Mixin` along with `#initialize` (nepalez)
814
+
815
+ The previous implementation required defaults and types to be stored in the class method `.initializer_builder`.
816
+ That made "container" syntax to support neither defaults nor types.
817
+
818
+ Now the `#initializer` is still defined via `instance_eval(code)` for efficiency. Some operations
819
+ (like default assignments, coercions, dry-type constraints etc.) cannot be implemented in this way.
820
+ They are made inside `##__after_initialize__` callback, that is biult via `default_method(&block)`
821
+ using instance evals.
822
+
823
+ ## [0.1.1] [2016-04-28]
824
+
825
+ ### Added
826
+ - `include Dry::Initializer.define -> do ... end` syntax (flash-gordon)
827
+
828
+ ## [0.1.0] [2016-04-26]
829
+
830
+ Class DSL splitted to mixin and container versions (thanks to @AMHOL for the idea).
831
+ Backward compatibility is broken.
832
+
833
+ ### Changed (backward-incompatible changes)
834
+ - Use `extend Dry::Initializer::Mixin` instead of `extend Dry::Initializer` (nepalez)
835
+
836
+ ### Added
837
+ - Use `include Dry::Initializer.define(&block)` as an alternative to extending the class (nepalez)
838
+
839
+ ## [0.0.1] [2016-04-09]
840
+
841
+ First public release
842
+
843
+ [0.1.0]: https://github.com/dry-rb/dry-initializer/compare/v0.0.1...v0.1.0
844
+ [0.1.1]: https://github.com/dry-rb/dry-initializer/compare/v0.1.0...v0.1.1
845
+ [0.2.0]: https://github.com/dry-rb/dry-initializer/compare/v0.1.1...v0.2.0
846
+ [0.2.1]: https://github.com/dry-rb/dry-initializer/compare/v0.2.0...v0.2.1
847
+ [0.2.1]: https://github.com/dry-rb/dry-initializer/compare/v0.2.0...v0.2.1
848
+ [0.3.0]: https://github.com/dry-rb/dry-initializer/compare/v0.2.1...v0.3.0
849
+ [0.3.1]: https://github.com/dry-rb/dry-initializer/compare/v0.3.0...v0.3.1
850
+ [0.3.2]: https://github.com/dry-rb/dry-initializer/compare/v0.3.1...v0.3.2
851
+ [0.3.3]: https://github.com/dry-rb/dry-initializer/compare/v0.3.2...v0.3.3
852
+ [0.4.0]: https://github.com/dry-rb/dry-initializer/compare/v0.3.3...v0.4.0
853
+ [0.5.0]: https://github.com/dry-rb/dry-initializer/compare/v0.4.0...v0.5.0
854
+ [0.6.0]: https://github.com/dry-rb/dry-initializer/compare/v0.5.0...v0.6.0
855
+ [0.7.0]: https://github.com/dry-rb/dry-initializer/compare/v0.6.0...v0.7.0
856
+ [0.8.0]: https://github.com/dry-rb/dry-initializer/compare/v0.7.0...v0.8.0
857
+ [0.8.1]: https://github.com/dry-rb/dry-initializer/compare/v0.8.0...v0.8.1
858
+ [0.9.0]: https://github.com/dry-rb/dry-initializer/compare/v0.8.1...v0.9.0
859
+ [0.9.1]: https://github.com/dry-rb/dry-initializer/compare/v0.9.0...v0.9.1
860
+ [0.9.2]: https://github.com/dry-rb/dry-initializer/compare/v0.9.1...v0.9.2
861
+ [0.9.3]: https://github.com/dry-rb/dry-initializer/compare/v0.9.2...v0.9.3
862
+ [0.10.0]: https://github.com/dry-rb/dry-initializer/compare/v0.9.3...v0.10.0
863
+ [0.10.1]: https://github.com/dry-rb/dry-initializer/compare/v0.10.0...v0.10.1
864
+ [0.10.2]: https://github.com/dry-rb/dry-initializer/compare/v0.10.1...v0.10.2
865
+ [0.11.0]: https://github.com/dry-rb/dry-initializer/compare/v0.10.2...v0.11.0
866
+ [1.0.0]: https://github.com/dry-rb/dry-initializer/compare/v0.11.0...v1.0.0
867
+ [1.1.0]: https://github.com/dry-rb/dry-initializer/compare/v1.0.0...v1.1.0
868
+ [1.1.1]: https://github.com/dry-rb/dry-initializer/compare/v1.1.0...v1.1.1
869
+ [1.1.2]: https://github.com/dry-rb/dry-initializer/compare/v1.1.1...v1.1.2
870
+ [1.1.3]: https://github.com/dry-rb/dry-initializer/compare/v1.1.2...v1.1.3
871
+ [1.2.0]: https://github.com/dry-rb/dry-initializer/compare/v1.1.3...v1.2.0
872
+ [1.3.0]: https://github.com/dry-rb/dry-initializer/compare/v1.2.0...v1.3.0
873
+ [1.4.0]: https://github.com/dry-rb/dry-initializer/compare/v1.3.0...v1.4.0
874
+ [1.4.1]: https://github.com/dry-rb/dry-initializer/compare/v1.4.0...v1.4.1
875
+ [2.0.0]: https://github.com/dry-rb/dry-initializer/compare/v1.4.1...v2.0.0
876
+ [2.1.0]: https://github.com/dry-rb/dry-initializer/compare/v2.0.0...v2.1.0
877
+ [2.2.0]: https://github.com/dry-rb/dry-initializer/compare/v2.1.0...v2.2.0
878
+ [2.3.0]: https://github.com/dry-rb/dry-initializer/compare/v2.2.0...v2.3.0
879
+ [2.4.0]: https://github.com/dry-rb/dry-initializer/compare/v2.3.0...v2.4.0
880
+ [2.6.0]: https://github.com/dry-rb/dry-initializer/compare/v2.4.0...v2.5.0
881
+ [2.6.0]: https://github.com/dry-rb/dry-initializer/compare/v2.5.0...v2.6.0
882
+ [3.0.0]: https://github.com/dry-rb/dry-initializer/compare/v2.5.0...v3.0.0
883
+ [3.0.1]: https://github.com/dry-rb/dry-initializer/compare/v3.0.0...v3.0.1