attributor 5.1.0 → 5.5

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -3
  3. data/CHANGELOG.md +145 -135
  4. data/attributor.gemspec +5 -6
  5. data/lib/attributor.rb +17 -2
  6. data/lib/attributor/attribute.rb +39 -9
  7. data/lib/attributor/dsl_compiler.rb +17 -9
  8. data/lib/attributor/exceptions.rb +5 -0
  9. data/lib/attributor/extras/field_selector.rb +4 -0
  10. data/lib/attributor/families/numeric.rb +19 -6
  11. data/lib/attributor/families/temporal.rb +16 -9
  12. data/lib/attributor/hash_dsl_compiler.rb +6 -6
  13. data/lib/attributor/smart_attribute_selector.rb +149 -0
  14. data/lib/attributor/type.rb +27 -4
  15. data/lib/attributor/types/bigdecimal.rb +7 -2
  16. data/lib/attributor/types/boolean.rb +7 -2
  17. data/lib/attributor/types/class.rb +2 -2
  18. data/lib/attributor/types/collection.rb +22 -5
  19. data/lib/attributor/types/container.rb +3 -3
  20. data/lib/attributor/types/csv.rb +5 -1
  21. data/lib/attributor/types/date.rb +9 -3
  22. data/lib/attributor/types/date_time.rb +8 -2
  23. data/lib/attributor/types/float.rb +4 -3
  24. data/lib/attributor/types/hash.rb +105 -21
  25. data/lib/attributor/types/integer.rb +7 -1
  26. data/lib/attributor/types/model.rb +2 -2
  27. data/lib/attributor/types/object.rb +5 -0
  28. data/lib/attributor/types/polymorphic.rb +3 -2
  29. data/lib/attributor/types/string.rb +20 -1
  30. data/lib/attributor/types/struct.rb +1 -1
  31. data/lib/attributor/types/symbol.rb +5 -0
  32. data/lib/attributor/types/tempfile.rb +4 -0
  33. data/lib/attributor/types/time.rb +7 -3
  34. data/lib/attributor/types/uri.rb +9 -1
  35. data/lib/attributor/version.rb +1 -1
  36. data/spec/attribute_spec.rb +42 -7
  37. data/spec/dsl_compiler_spec.rb +16 -6
  38. data/spec/extras/field_selector/field_selector_spec.rb +9 -0
  39. data/spec/hash_dsl_compiler_spec.rb +2 -2
  40. data/spec/smart_attribute_selector_spec.rb +272 -0
  41. data/spec/support/integers.rb +7 -0
  42. data/spec/type_spec.rb +1 -1
  43. data/spec/types/bigdecimal_spec.rb +8 -0
  44. data/spec/types/boolean_spec.rb +10 -0
  45. data/spec/types/class_spec.rb +0 -1
  46. data/spec/types/collection_spec.rb +16 -0
  47. data/spec/types/date_spec.rb +9 -0
  48. data/spec/types/date_time_spec.rb +9 -0
  49. data/spec/types/float_spec.rb +8 -0
  50. data/spec/types/hash_spec.rb +181 -9
  51. data/spec/types/integer_spec.rb +10 -1
  52. data/spec/types/model_spec.rb +14 -3
  53. data/spec/types/string_spec.rb +10 -0
  54. data/spec/types/temporal_spec.rb +5 -1
  55. data/spec/types/time_spec.rb +9 -0
  56. data/spec/types/uri_spec.rb +9 -0
  57. metadata +24 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe4a2dca77307723d8c18e4f37ded9cba8e54657
4
- data.tar.gz: 175d9d21dd78aaba4e6c534559290cb79d3bf3a2
3
+ metadata.gz: 30cd524aa1a60bb34487915e2201e20b075f8eaf
4
+ data.tar.gz: 4a9776a1a772b00636a46caec55f583aa75d54f4
5
5
  SHA512:
6
- metadata.gz: 89de22ecae27da14b59f57b2ea87d3552c6d1dbdd338e07934bc29031fd4e65b664f4faf04fb50f56b2e3687cde7580ba217562a413856fa8cdb403c9bc4a335
7
- data.tar.gz: d8beb7bba6e226b84d1608d080800e65ce632d3b9af0daeb6fa7415f0477d307d63ac9267b4ffd659fe846b9f1b0b3012d4853d8a1bb6a3d4bad4ff037aaa10b
6
+ metadata.gz: a5a4832825c92b5530352b626ae281c134aa215f167c633a7912b22cee2927fde696d07b92bfd6159b0e88db4dc69b19b38a289181cb523e0c961005608e4f86
7
+ data.tar.gz: a44680f8509acf463ac0c4a22a872db8456300745d01b5c4a31a597bd17760d995e5d6ce26120d998f8df5c4c06fe2d11e7e00c35959f6c987860059425af663
@@ -1,11 +1,12 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.5
5
- - 2.3.1
4
+ - 2.4
5
+ - 2.5
6
+ - 2.6
7
+ - 2.7
6
8
  script:
7
9
  - bundle exec rspec spec
8
- - bundle exec rubocop --format=clang
9
10
  branches:
10
11
  only:
11
12
  - master
@@ -2,38 +2,57 @@
2
2
 
3
3
  ## next
4
4
 
5
+ ## 5.5 (21/08/2020)
6
+
7
+ - JSON-schema support. Enhanced all of the types to suppport describing themselves as JSON-schema format (`.as_json_schema`). This description includes a few `x-*` extensions to capture some information that Attributor supports, that JSON-schema does not.
8
+
9
+ ## 5.3 (24/04/2020)
10
+
11
+ - Fixed deprecation warnings in Ruby 2.7
12
+
13
+ ## 5.2.1 (25/08/2019)
14
+
15
+ - Propertly pass options down when dumping an Model
16
+
17
+ ## 5.2 (12/09/2017)
18
+
19
+ - Fixed describing `Hash` with no keys defined, to still use a given example (no example outputted before this)
20
+ - Fix bug that would occur when defining an attribute carrying a reference object, for which the reference type didn't have `attributes` (for example a Collection).
21
+ - Allows an attribute to override the reference object through its options of its parent (even when its containing object already has one defined).
22
+ - Built code to generate examples in a smarter way when complex conditional requirements are specified.
23
+
5
24
  ## 5.1
6
25
 
7
- * Added `Polymorphic` type. See [polymorphics.rb](spec/support/polymorphics.rb) for example usage.
26
+ - Added `Polymorphic` type. See [polymorphics.rb](spec/support/polymorphics.rb) for example usage.
8
27
 
9
28
  ## 5.0.2
10
29
 
11
- * Introduce the `Dumpable` (empty) module as an interface to indicate that instances of types that include it
12
- will respond to the `.dump` method, as a way to convert their internal substructure to primitive Ruby objects.
13
- * Currently the only two directly dumpable types are Collection and Hash (with the caveat that there are several others that derive from them..i.e., CSV, Model, etc...)
14
- * The rest of types have `native_types` that are already Ruby primitive Objects.
15
- * Fixed Hash and Model requirements to treat nil values as missing keys (to be compatible with the `required: true` option on an attribute).
30
+ - Introduce the `Dumpable` (empty) module as an interface to indicate that instances of types that include it
31
+ will respond to the `.dump` method, as a way to convert their internal substructure to primitive Ruby objects.
32
+ - Currently the only two directly dumpable types are Collection and Hash (with the caveat that there are several others that derive from them..i.e., CSV, Model, etc...)
33
+ - The rest of types have `native_types` that are already Ruby primitive Objects.
34
+ - Fixed Hash and Model requirements to treat nil values as missing keys (to be compatible with the `required: true` option on an attribute).
16
35
 
17
36
  ## 5.0.1
18
37
 
19
- * Fix bug that made Struct/Models skip validation of requirements using the `requires` DSL
38
+ - Fix bug that made Struct/Models skip validation of requirements using the `requires` DSL
20
39
 
21
40
  ## 5.0
22
41
 
23
- * Changed `FieldSelector` sub-attribute selection to use `{}` instead of `()`.
24
-
42
+ - Changed `FieldSelector` sub-attribute selection to use `{}` instead of `()`.
25
43
 
26
44
  ## 4.2.0
27
45
 
28
- * Added an "anonymous" DSL for base `Attributor::Type` which is reported in its `.describe` call.
29
- * This is a simple documentation bit, that might help the clients to document the type properly (i.e. treat it as if the type was anonymously defined whenever is used, rather than reachable by id/name from anywhere)
46
+ - Added an "anonymous" DSL for base `Attributor::Type` which is reported in its `.describe` call.
47
+
48
+ - This is a simple documentation bit, that might help the clients to document the type properly (i.e. treat it as if the type was anonymously defined whenever is used, rather than reachable by id/name from anywhere)
30
49
 
31
- * Built advanced attribute requirements for `Struct`,`Model` and `Hash` types. Those requirements allow you to define things like:
32
- * A list of attributes that are required (equivalent to defining the required: true bit at each of the attributes)
33
- * At most (n) attributes from a group can be passed in
34
- * At least (n) attributes from a group are required
35
- * Exactly (n) attributes from a group are required
36
- * Example:
50
+ - Built advanced attribute requirements for `Struct`,`Model` and `Hash` types. Those requirements allow you to define things like:
51
+ - A list of attributes that are required (equivalent to defining the required: true bit at each of the attributes)
52
+ - At most (n) attributes from a group can be passed in
53
+ - At least (n) attributes from a group are required
54
+ - Exactly (n) attributes from a group are required
55
+ - Example:
37
56
  ```
38
57
  requires ‘id’, ‘name’
39
58
  requires.all ‘id’, ‘name’ # Equivalent to above
@@ -42,7 +61,7 @@ will respond to the `.dump` method, as a way to convert their internal substruct
42
61
  requires.at_least(1).of ‘rock’, ‘pop’
43
62
  requires.exactly(2).of ‘one’, ‘two’, ’three’
44
63
  ```
45
- * Same example expressed inside a block if so desired
64
+ - Same example expressed inside a block if so desired
46
65
  ```
47
66
  requires do
48
67
  all 'id', 'name
@@ -54,167 +73,158 @@ will respond to the `.dump` method, as a way to convert their internal substruct
54
73
 
55
74
  ## 4.1.0
56
75
 
57
- * Added a `Class` type (useful to avoid demodulization coercions etc...)
58
- * Added `Attributor::FieldSelector` type for parsing hierarchical field
76
+ - Added a `Class` type (useful to avoid demodulization coercions etc...)
77
+ - Added `Attributor::FieldSelector` type for parsing hierarchical field
59
78
  selection hashes from a string. This is similar to the partial `fields`
60
79
  parameter in Google APIs, or the `fields` parameter in the Facebook's Graph
61
80
  API.
62
- * For example: the string `'one,two(a,b)'` would select two top-level fields
63
- named 'one' and 'two', retrieving the entire contents of 'one', and only
64
- the 'a' and 'b' sub-fields for 'two'. The type will parse the above string
65
- into the hash: `{one: true, two: {a: true, b: true}}`.
66
- * This type is not automatically required by Attributor. To require it use:
67
- `require 'attributor/extras/field_selector'.
68
- * This type also depends upon the 'parslet' gem.
81
+ - For example: the string `'one,two(a,b)'` would select two top-level fields
82
+ named 'one' and 'two', retrieving the entire contents of 'one', and only
83
+ the 'a' and 'b' sub-fields for 'two'. The type will parse the above string
84
+ into the hash: `{one: true, two: {a: true, b: true}}`.
85
+ - This type is not automatically required by Attributor. To require it use:
86
+ `require 'attributor/extras/field_selector'.
87
+ - This type also depends upon the 'parslet' gem.
69
88
 
70
89
  ## 4.0.1
71
90
 
72
- * `Attribute#check_option!` now calls `load` on any provided value.
73
-
91
+ - `Attribute#check_option!` now calls `load` on any provided value.
74
92
 
75
93
  ## 4.0.0
76
94
 
77
- * Changed the expectation of the value for an `:example` option of an attribute:
78
- * Before, passing an array of values would indicate that those were a few possible examples for it.
79
- * Now, any value (except the already existing special regexp or a proc) for an example will need to be of a native type (or coercible to it). This means that an attribute of type `Collection` can take an array example (and be taken as the whole thing)
80
- * If anybody wants to provide multiple examples for an attribute they can write a proc, and make it return the different ones.
95
+ - Changed the expectation of the value for an `:example` option of an attribute:
96
+ - Before, passing an array of values would indicate that those were a few possible examples for it.
97
+ - Now, any value (except the already existing special regexp or a proc) for an example will need to be of a native type (or coercible to it). This means that an attribute of type `Collection` can take an array example (and be taken as the whole thing)
98
+ - If anybody wants to provide multiple examples for an attribute they can write a proc, and make it return the different ones.
81
99
 
82
100
  ## 3.0.1
83
101
 
84
- * Fixed bug with example Hashes where `[]` with a key not in the hash would throw a `NoMethodError`.
85
- * Fixed bug in `Hash#get` for Hashes without predefined keys. It would throw an error if given a key not present in the hash's contents.
86
-
102
+ - Fixed bug with example Hashes where `[]` with a key not in the hash would throw a `NoMethodError`.
103
+ - Fixed bug in `Hash#get` for Hashes without predefined keys. It would throw an error if given a key not present in the hash's contents.
87
104
 
88
105
  ## 3.0.0
89
106
 
90
- * Small enhancements on `describe` for types
91
- * avoid creating empty `:attributes` key for `Model`
92
- * ensure embedding `key_type` in `Hash` using `shallow` mode
93
- * Added `Hash#delete`.
94
- * Changed the schema for describing `Hash` to use `attributes` instead of `keys`
95
- * It makes more sense, and it is compatible with Model and Structs too.
96
- * Undefine JRuby package helper methods in `Model` (org, java...)
97
- * Added support to `Collection.load` for any value that responds to `to_a`
98
- * Fixed `Collection.validate` to complain when value object is not a valida type
99
- * Fixed bug where defining an attribute that references a `Collection` would not properly support defining sub-attributes in a provided block.
100
- * Enhanced the type/attribute `describe` methods of types so that they generate an example if an `example` argument is passed in.
101
- * Complex (sub-structured) types will not output examples, only 'leaf' ones.
102
- * Improved handling of exceptions during attribute definitions for `Hash`/`Model` that would previously leave the set of attributes in an undefined state. Now, any attempts to use the type will throw an `InvalidDefinition` exception and include the original exception. (#127)
103
- * Removed `undef :empty?` from `Model`
104
- * Made `Collection` a subclass of Array, and `load` create new instances of it.
105
- * Built in proper loading and validation of any `Attribute#example` when the `:example` option is used.
106
-
107
+ - Small enhancements on `describe` for types
108
+ - avoid creating empty `:attributes` key for `Model`
109
+ - ensure embedding `key_type` in `Hash` using `shallow` mode
110
+ - Added `Hash#delete`.
111
+ - Changed the schema for describing `Hash` to use `attributes` instead of `keys`
112
+ - It makes more sense, and it is compatible with Model and Structs too.
113
+ - Undefine JRuby package helper methods in `Model` (org, java...)
114
+ - Added support to `Collection.load` for any value that responds to `to_a`
115
+ - Fixed `Collection.validate` to complain when value object is not a valida type
116
+ - Fixed bug where defining an attribute that references a `Collection` would not properly support defining sub-attributes in a provided block.
117
+ - Enhanced the type/attribute `describe` methods of types so that they generate an example if an `example` argument is passed in.
118
+ - Complex (sub-structured) types will not output examples, only 'leaf' ones.
119
+ - Improved handling of exceptions during attribute definitions for `Hash`/`Model` that would previously leave the set of attributes in an undefined state. Now, any attempts to use the type will throw an `InvalidDefinition` exception and include the original exception. (#127)
120
+ - Removed `undef :empty?` from `Model`
121
+ - Made `Collection` a subclass of Array, and `load` create new instances of it.
122
+ - Built in proper loading and validation of any `Attribute#example` when the `:example` option is used.
107
123
 
108
124
  ## 2.6.1
109
125
 
110
- * Add the `:custom_data` option for attributes. This is a hash that is passed through to `describe` - Attributor does no processing or handling of this option.
111
- * Added `Type.family` which returns a more-generic "family name". It's defined for all built-in types, and is included in `Type.describe`.
112
- * Cleanup and bug fixes around example generation for `Model`, `Struct` and `Hash`.
113
- * Avoid creating method accessors for true `Hash` types (only `[]` accessors)
114
- * Fix common hash methods created for example instances (to play well with lazy attributes)
115
- * Avoid storing the `Hash#insensitive_map` unless insensitivity enabled
126
+ - Add the `:custom_data` option for attributes. This is a hash that is passed through to `describe` - Attributor does no processing or handling of this option.
127
+ - Added `Type.family` which returns a more-generic "family name". It's defined for all built-in types, and is included in `Type.describe`.
128
+ - Cleanup and bug fixes around example generation for `Model`, `Struct` and `Hash`.
129
+ - Avoid creating method accessors for true `Hash` types (only `[]` accessors)
130
+ - Fix common hash methods created for example instances (to play well with lazy attributes)
131
+ - Avoid storing the `Hash#insensitive_map` unless insensitivity enabled
116
132
 
117
133
  ## 2.6.0
118
134
 
119
- * Fixed bug in `example_mixin` where lazy_attributes were not evaluated.
120
- * Fixed bug in `Hash` where the class would refuse to load from another `Attributor::Hash` when there were no keys defined and they were seemingly compatible.
121
- * Fixed a `Hash.dump` bug where nil attribute values would transitively be `dumpe`d therefore causing a nil dereference.
122
- * Hardened the `dump`ing of types to support nil values.
123
- * Fix `attribute.example` to actually accept native types (that are not only Strings)
124
- * Fixed bug where `Hash#get` would insert a nil value if asked for a key that was not present in the hash.
125
- * Fixed bug in `Hash.from_hash` where it would add nil values for keys that are defined on the type but not present in the input.
126
- * Added `Hash#merge` that works with two identically-typed hashes
127
- * Added `Hash#each_pair` for better duck-type compatibility with ::Hash.
128
-
135
+ - Fixed bug in `example_mixin` where lazy_attributes were not evaluated.
136
+ - Fixed bug in `Hash` where the class would refuse to load from another `Attributor::Hash` when there were no keys defined and they were seemingly compatible.
137
+ - Fixed a `Hash.dump` bug where nil attribute values would transitively be `dumpe`d therefore causing a nil dereference.
138
+ - Hardened the `dump`ing of types to support nil values.
139
+ - Fix `attribute.example` to actually accept native types (that are not only Strings)
140
+ - Fixed bug where `Hash#get` would insert a nil value if asked for a key that was not present in the hash.
141
+ - Fixed bug in `Hash.from_hash` where it would add nil values for keys that are defined on the type but not present in the input.
142
+ - Added `Hash#merge` that works with two identically-typed hashes
143
+ - Added `Hash#each_pair` for better duck-type compatibility with ::Hash.
129
144
 
130
145
  ## 2.5.0
131
146
 
132
- * Partial support for defining `:default` values through Procs.
133
- * Note: this is only "partially" supported the `parent` argument of the Proc will NOT contain the correct attribute parent yet. It will contain a fake class, that will loudly complain about any attempt to use any of its methods.
134
- * Fixed `Model.example` to properly handle the case when no attributes are defined on the class.
135
- * `Model#dump` now issues a warning if its contents have keys for attributes not present on the class. The unknown contents are not dumped.
136
- * `Hash.load` now supports loading any value that responds to `to_hash`.
137
- * `Time`, `DateTime`, and `Date` now all return ISO 8601 formatted values from `.dump` (via calling `iso8601` on the value).
138
- * Added `Type.id`, a unique value based on the type's class name.
139
-
147
+ - Partial support for defining `:default` values through Procs.
148
+ - Note: this is only "partially" supported the `parent` argument of the Proc will NOT contain the correct attribute parent yet. It will contain a fake class, that will loudly complain about any attempt to use any of its methods.
149
+ - Fixed `Model.example` to properly handle the case when no attributes are defined on the class.
150
+ - `Model#dump` now issues a warning if its contents have keys for attributes not present on the class. The unknown contents are not dumped.
151
+ - `Hash.load` now supports loading any value that responds to `to_hash`.
152
+ - `Time`, `DateTime`, and `Date` now all return ISO 8601 formatted values from `.dump` (via calling `iso8601` on the value).
153
+ - Added `Type.id`, a unique value based on the type's class name.
140
154
 
141
155
  ## 2.4.0
142
156
 
143
- * `Model` is now a subclass of `Hash`.
144
- * The interface for `Model` instances is almost entirely unchanged, except for the addition of `Hash`-like methods (i.e., you can now do `some_model[:key]` to access attributes).
145
- * This fixes numerous incompatabilities between models and hashes, as well as confusing differences between the behavior when loading a model vs a hash.
146
- * `String.load` now raises `IncompatibleTypeError` for `Enumerable` values.
147
- * Added `Symbol` type, use with caution as it will automatically call `#to_sym` on anything loaded.
157
+ - `Model` is now a subclass of `Hash`.
158
+ - The interface for `Model` instances is almost entirely unchanged, except for the addition of `Hash`-like methods (i.e., you can now do `some_model[:key]` to access attributes).
159
+ - This fixes numerous incompatabilities between models and hashes, as well as confusing differences between the behavior when loading a model vs a hash.
160
+ - `String.load` now raises `IncompatibleTypeError` for `Enumerable` values.
161
+ - Added `Symbol` type, use with caution as it will automatically call `#to_sym` on anything loaded.
148
162
 
149
163
  ## 2.3.0
150
164
 
151
- * Added `recurse` option to `Type.load` that is used by `Model` and `Hash` to force the loading of values (specifically, so that default values are assigned) even if the loaded value is `nil`.
152
- * Fix `Attributor::CSV` to dump `String` values and generate `String` examples.
153
- * Default values of `false` now work correctly.
154
- * Added `BigDecimal`, `Date` and `Time` types
155
- * `DateTime.load` now raises `CoercionError` (instead of returning `nil`) if given values that can not coerced properly.
156
- * `Hash.dump` now first calls `Hash.load`, and correctly uses defined value types for dumping.
157
- * Added `Hash#get`, for retrieving keys using the same logic the `case_insensitive_load` and `allow_extra` with defined `extra` key.
158
-
165
+ - Added `recurse` option to `Type.load` that is used by `Model` and `Hash` to force the loading of values (specifically, so that default values are assigned) even if the loaded value is `nil`.
166
+ - Fix `Attributor::CSV` to dump `String` values and generate `String` examples.
167
+ - Default values of `false` now work correctly.
168
+ - Added `BigDecimal`, `Date` and `Time` types
169
+ - `DateTime.load` now raises `CoercionError` (instead of returning `nil`) if given values that can not coerced properly.
170
+ - `Hash.dump` now first calls `Hash.load`, and correctly uses defined value types for dumping.
171
+ - Added `Hash#get`, for retrieving keys using the same logic the `case_insensitive_load` and `allow_extra` with defined `extra` key.
159
172
 
160
173
  ## 2.2.1
161
174
 
162
- * Dumping attributes will now load the values if they're not in the native type.
163
- * `Model.valid_type?` now accepts hashes.
164
- * `Hash`:
165
- * Added `:has_key?` to delegation
166
-
175
+ - Dumping attributes will now load the values if they're not in the native type.
176
+ - `Model.valid_type?` now accepts hashes.
177
+ - `Hash`:
178
+ - Added `:has_key?` to delegation
167
179
 
168
180
  ## 2.2.0
169
181
 
170
- * Fix example generation for Hash and Collection to handle a non-Array context parameter.
171
- * Hash:
172
- * Added additional options:
173
- * `:case_insensitive_load` for string-keyed hashes. This allows loading hashes with keys that do not exactly match the case defined in the hash.
174
- * Added `:allow_extras` option to allow handling of undefined keys when loading.
175
- * Added `Hash#set` to encapsulate the above options and attribute loading.
176
- * Added `extra` command in the `keys` DSL, which lets you define a key (whose value should be a Hash), to group any unspecified keys during load.
177
-
182
+ - Fix example generation for Hash and Collection to handle a non-Array context parameter.
183
+ - Hash:
184
+ - Added additional options:
185
+ - `:case_insensitive_load` for string-keyed hashes. This allows loading hashes with keys that do not exactly match the case defined in the hash.
186
+ - Added `:allow_extras` option to allow handling of undefined keys when loading.
187
+ - Added `Hash#set` to encapsulate the above options and attribute loading.
188
+ - Added `extra` command in the `keys` DSL, which lets you define a key (whose value should be a Hash), to group any unspecified keys during load.
178
189
 
179
190
  ## 2.1.0
180
191
 
181
- * Structs now inherit type-level options from their reference.
182
- * Add Collection subclasses for CSVs and Ids
183
- * CSV type for Collection of values serialized as comma-separated strings.
184
- * Ids type. A helper for creating CSVs with members matching a given a type's :identity option.
185
- * Allow instances of Models to be initialized with initial data.
186
- * Supported formats for the data are equivalent to the loading formats (i.e. ruby Hash, a JSON string or another instance of the same model type).
187
- * Improved context reporting in errors
188
- * Added contextual information while loading and dumping attributes.
189
- * `load` takes a new `context` argument (defaulting to a system-wide root) in the form of an array of parent segments.
190
- * `validate` takes a `context` argument that (instead of a string) is now an array of parent segments.
191
- * `dump` takes a `context:` option parameter of the same type
192
- * Enhanced error messages to report the correct context scope.
193
- * Make Attribute assignments in models to report a special context (not the attributor root)
194
- * Instead of reporting "$." as the context , when doing model.field_name=value, they'll now report "assignment.of(field_name)" instead
195
- * Truncate the length of values when reporting loading errors when they're long (i.e. >500 chars)
196
- * `Model.attributes` may now be called more than once to set add or replace attributes. The exact behavior depends upon the types of the attributes being added or replaced. See [model_spec.rb](spec/types/model_spec.rb) for examples.
197
- * Greately enhanced Hash type with individual key specification (rather than
192
+ - Structs now inherit type-level options from their reference.
193
+ - Add Collection subclasses for CSVs and Ids
194
+ - CSV type for Collection of values serialized as comma-separated strings.
195
+ - Ids type. A helper for creating CSVs with members matching a given a type's :identity option.
196
+ - Allow instances of Models to be initialized with initial data.
197
+ - Supported formats for the data are equivalent to the loading formats (i.e. ruby Hash, a JSON string or another instance of the same model type).
198
+ - Improved context reporting in errors
199
+ - Added contextual information while loading and dumping attributes.
200
+ - `load` takes a new `context` argument (defaulting to a system-wide root) in the form of an array of parent segments.
201
+ - `validate` takes a `context` argument that (instead of a string) is now an array of parent segments.
202
+ - `dump` takes a `context:` option parameter of the same type
203
+ - Enhanced error messages to report the correct context scope.
204
+ - Make Attribute assignments in models to report a special context (not the attributor root)
205
+ - Instead of reporting "\$." as the context , when doing model.field_name=value, they'll now report "assignment.of(field_name)" instead
206
+ - Truncate the length of values when reporting loading errors when they're long (i.e. >500 chars)
207
+ - `Model.attributes` may now be called more than once to set add or replace attributes. The exact behavior depends upon the types of the attributes being added or replaced. See [model_spec.rb](spec/types/model_spec.rb) for examples.
208
+ - Greately enhanced Hash type with individual key specification (rather than
198
209
  simply defining the types of keys)
199
- * Loaded Hash types now return instances of the class rather than a simple Ruby Hash.
200
- * Introduced a new FileUpload type. This can be easily used in Web servers to map incoming multipart file uploads.
201
- * Introduced a new Tempfile type.
202
-
210
+ - Loaded Hash types now return instances of the class rather than a simple Ruby Hash.
211
+ - Introduced a new FileUpload type. This can be easily used in Web servers to map incoming multipart file uploads.
212
+ - Introduced a new Tempfile type.
203
213
 
204
214
  ## 2.0.0
205
215
 
206
- * Added new exception subtypes (load methods return more precise errors now)
207
- * Changed ```Attributor::Model``` to be a class instead of module.
208
- * Improved handling of ```Attributor::Model``` examples:
209
- * Support creating examples with specific values. i.e.:
216
+ - Added new exception subtypes (load methods return more precise errors now)
217
+ - Changed `Attributor::Model` to be a class instead of module.
218
+ - Improved handling of `Attributor::Model` examples:
219
+ - Support creating examples with specific values. i.e.:
210
220
  ```ruby
211
221
  person = Person.example(name: "Bob")
212
222
  person.name # => "Bob"
213
223
  ```
214
- * Example values are now lazily initialized when used.
215
- * Terminate sub-attribute generation after ```Attributor::Model::MAX_EXAMPLE_DEPTH``` levels to prevent infinite generation.
216
- * Added additional options for Attribute :example values:
217
- * explicit nil values
218
- * procs that take 2 arguments now receive the context as the second argument.
219
- * Circular references are now detected and handled in validation and dumping.
220
- * Fixed bug with Model attribute accessors when using false values.
224
+ - Example values are now lazily initialized when used.
225
+ - Terminate sub-attribute generation after `Attributor::Model::MAX_EXAMPLE_DEPTH` levels to prevent infinite generation.
226
+ - Added additional options for Attribute :example values:
227
+ - explicit nil values
228
+ - procs that take 2 arguments now receive the context as the second argument.
229
+ - Circular references are now detected and handled in validation and dumping.
230
+ - Fixed bug with Model attribute accessors when using false values.
@@ -25,19 +25,18 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_development_dependency 'rspec', '~> 3'
27
27
  spec.add_development_dependency 'rspec-its'
28
- spec.add_development_dependency 'rspec-collection_matchers', '~> 1'
29
- spec.add_development_dependency('yard', ['~> 0.8.7'])
30
- spec.add_development_dependency('backports', ['~> 3'])
28
+ spec.add_development_dependency 'rspec-collection_matchers'
29
+ spec.add_development_dependency('yard')
31
30
  spec.add_development_dependency('yardstick', ['~> 0'])
32
31
  spec.add_development_dependency('bundler', ['>= 0'])
33
32
  spec.add_development_dependency('rake-notes', ['~> 0'])
34
33
  spec.add_development_dependency('coveralls')
35
34
  spec.add_development_dependency('guard', ['~> 2'])
36
35
  spec.add_development_dependency('guard-rspec', ['~> 4'])
37
- spec.add_development_dependency('pry', ['~> 0'])
36
+ spec.add_development_dependency('pry')
38
37
  if RUBY_PLATFORM !~ /java/
39
- spec.add_development_dependency('pry-byebug', ['~> 1'])
40
- spec.add_development_dependency('pry-stack_explorer', ['~> 0'])
38
+ spec.add_development_dependency('pry-byebug')
39
+ spec.add_development_dependency('pry-stack_explorer')
41
40
  end
42
41
  spec.add_development_dependency 'fuubar'
43
42
  spec.add_development_dependency 'rubocop'
@@ -2,7 +2,7 @@ require 'json'
2
2
  require 'randexp'
3
3
 
4
4
  require 'hashie'
5
-
5
+ require 'active_support/concern'
6
6
  require 'digest/sha1'
7
7
 
8
8
  module Attributor
@@ -14,6 +14,7 @@ module Attributor
14
14
  require_relative 'attributor/dsl_compiler'
15
15
  require_relative 'attributor/hash_dsl_compiler'
16
16
  require_relative 'attributor/attribute_resolver'
17
+ require_relative 'attributor/smart_attribute_selector'
17
18
 
18
19
  require_relative 'attributor/example_mixin'
19
20
 
@@ -28,7 +29,7 @@ module Attributor
28
29
  def self.resolve_type(attr_type, options = {}, constructor_block = nil)
29
30
  klass = self.find_type(attr_type)
30
31
 
31
- return klass.construct(constructor_block, options) if klass.constructable?
32
+ return klass.construct(constructor_block, **options) if klass.constructable?
32
33
  raise AttributorException, "Type: #{attr_type} does not support anonymous generation" if constructor_block
33
34
 
34
35
  klass
@@ -72,6 +73,20 @@ module Attributor
72
73
  inspection
73
74
  end
74
75
 
76
+ def self.recursive_to_h(val)
77
+ if val.is_a? Array
78
+ val.map { |v| recursive_to_h(v) }
79
+ elsif val.nil?
80
+ nil
81
+ elsif val.respond_to?(:to_h)
82
+ val.to_h.each_with_object({}) do |(name, inner_val), hash|
83
+ hash[name] = recursive_to_h(inner_val)
84
+ end
85
+ else
86
+ val
87
+ end
88
+ end
89
+
75
90
  MODULE_PREFIX = 'Attributor::'.freeze
76
91
  MODULE_PREFIX_REGEX = ::Regexp.new(MODULE_PREFIX)
77
92