attributor 2.6.1 → 3.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/CHANGELOG.md +38 -26
- data/lib/attributor.rb +8 -7
- data/lib/attributor/attribute.rb +41 -25
- data/lib/attributor/dsl_compiler.rb +7 -1
- data/lib/attributor/type.rb +10 -8
- data/lib/attributor/types/collection.rb +49 -10
- data/lib/attributor/types/csv.rb +8 -1
- data/lib/attributor/types/hash.rb +45 -11
- data/lib/attributor/types/model.rb +13 -10
- data/lib/attributor/types/string.rb +4 -4
- data/lib/attributor/types/uri.rb +57 -0
- data/lib/attributor/version.rb +1 -1
- data/spec/attribute_spec.rb +136 -64
- data/spec/support/models.rb +7 -2
- data/spec/type_spec.rb +13 -3
- data/spec/types/collection_spec.rb +66 -19
- data/spec/types/csv_spec.rb +14 -3
- data/spec/types/hash_spec.rb +134 -10
- data/spec/types/ids_spec.rb +1 -1
- data/spec/types/model_spec.rb +78 -18
- data/spec/types/string_spec.rb +6 -8
- data/spec/types/uri_spec.rb +12 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9b60ce0b5ac69797dca8bc43ce9164e8a666eeb
|
4
|
+
data.tar.gz: d87a417b41105b3ed4ae10098bd14542d88d7f96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 660346014295ff874c70f0cc79931b98c109c0034e1b235f516108aa5857fa71688a2a2fcd7aab8c9636c91b87a64d1b82d09ae1a7d247b0bf7a23cf232a80d2
|
7
|
+
data.tar.gz: 174c4d2859d2ad0611c55b3c16c70eaa80440fcdee5308fe84a917192d624383e65bfae19c5bd593732ac59ba0d13d908e4c018406f0256fe0f1c30864911fc1
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,26 @@
|
|
1
|
-
Attributor Changelog
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
# Attributor Changelog
|
2
|
+
|
3
|
+
## 3.0.0
|
4
|
+
|
5
|
+
* Small enhancements on `describe` for types
|
6
|
+
* avoid creating empty `:attributes` key for `Model`
|
7
|
+
* ensure embedding `key_type` in `Hash` using `shallow` mode
|
8
|
+
* Added `Hash#delete`.
|
9
|
+
* Changed the schema for describing `Hash` to use `attributes` instead of `keys`
|
10
|
+
* It makes more sense, and it is compatible with Model and Structs too.
|
11
|
+
* Undefine JRuby package helper methods in `Model` (org, java...)
|
12
|
+
* Added support to `Collection.load` for any value that responds to `to_a`
|
13
|
+
* Fixed `Collection.validate` to complain when value object is not a valida type
|
14
|
+
* Fixed bug where defining an attribute that references a `Collection` would not properly support defining sub-attributes in a provided block.
|
15
|
+
* Enhanced the type/attribute `describe` methods of types so that they generate an example if an `example` argument is passed in.
|
16
|
+
* Complex (sub-structured) types will not output examples, only 'leaf' ones.
|
17
|
+
* 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)
|
18
|
+
* Removed `undef :empty?` from `Model`
|
19
|
+
* Made `Collection` a subclass of Array, and `load` create new instances of it.
|
20
|
+
* Built in proper loading and validation of any `Attribute#example` when the `:example` option is used.
|
21
|
+
|
22
|
+
|
23
|
+
## 2.6.1
|
9
24
|
|
10
25
|
* 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.
|
11
26
|
* Added `Type.family` which returns a more-generic "family name". It's defined for all built-in types, and is included in `Type.describe`.
|
@@ -14,8 +29,7 @@ next
|
|
14
29
|
* Fix common hash methods created for example instances (to play well with lazy attributes)
|
15
30
|
* Avoid storing the `Hash#insensitive_map` unless insensitivity enabled
|
16
31
|
|
17
|
-
2.6.0
|
18
|
-
-----
|
32
|
+
## 2.6.0
|
19
33
|
|
20
34
|
* Fixed bug in `example_mixin` where lazy_attributes were not evaluated.
|
21
35
|
* 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.
|
@@ -27,8 +41,8 @@ next
|
|
27
41
|
* Added `Hash#merge` that works with two identically-typed hashes
|
28
42
|
* Added `Hash#each_pair` for better duck-type compatibility with ::Hash.
|
29
43
|
|
30
|
-
|
31
|
-
|
44
|
+
|
45
|
+
## 2.5.0
|
32
46
|
|
33
47
|
* Partial support for defining `:default` values through Procs.
|
34
48
|
* 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.
|
@@ -38,17 +52,16 @@ next
|
|
38
52
|
* `Time`, `DateTime`, and `Date` now all return ISO 8601 formatted values from `.dump` (via calling `iso8601` on the value).
|
39
53
|
* Added `Type.id`, a unique value based on the type's class name.
|
40
54
|
|
41
|
-
2.4.0
|
42
|
-
------
|
43
55
|
|
44
|
-
|
56
|
+
## 2.4.0
|
57
|
+
|
58
|
+
* `Model` is now a subclass of `Hash`.
|
45
59
|
* 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).
|
46
60
|
* This fixes numerous incompatabilities between models and hashes, as well as confusing differences between the behavior when loading a model vs a hash.
|
47
61
|
* `String.load` now raises `IncompatibleTypeError` for `Enumerable` values.
|
48
|
-
* Added `Symbol` type, use with caution as it will automatically call `#to_sym` on anything loaded.
|
62
|
+
* Added `Symbol` type, use with caution as it will automatically call `#to_sym` on anything loaded.
|
49
63
|
|
50
|
-
2.3.0
|
51
|
-
------
|
64
|
+
## 2.3.0
|
52
65
|
|
53
66
|
* 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`.
|
54
67
|
* Fix `Attributor::CSV` to dump `String` values and generate `String` examples.
|
@@ -59,16 +72,15 @@ next
|
|
59
72
|
* Added `Hash#get`, for retrieving keys using the same logic the `case_insensitive_load` and `allow_extra` with defined `extra` key.
|
60
73
|
|
61
74
|
|
62
|
-
2.2.1
|
63
|
-
------
|
75
|
+
## 2.2.1
|
64
76
|
|
65
77
|
* Dumping attributes will now load the values if they're not in the native type.
|
66
78
|
* `Model.valid_type?` now accepts hashes.
|
67
79
|
* `Hash`:
|
68
80
|
* Added `:has_key?` to delegation
|
69
81
|
|
70
|
-
|
71
|
-
|
82
|
+
|
83
|
+
## 2.2.0
|
72
84
|
|
73
85
|
* Fix example generation for Hash and Collection to handle a non-Array context parameter.
|
74
86
|
* Hash:
|
@@ -78,8 +90,8 @@ next
|
|
78
90
|
* Added `Hash#set` to encapsulate the above options and attribute loading.
|
79
91
|
* 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.
|
80
92
|
|
81
|
-
|
82
|
-
|
93
|
+
|
94
|
+
## 2.1.0
|
83
95
|
|
84
96
|
* Structs now inherit type-level options from their reference.
|
85
97
|
* Add Collection subclasses for CSVs and Ids
|
@@ -103,8 +115,8 @@ next
|
|
103
115
|
* Introduced a new FileUpload type. This can be easily used in Web servers to map incoming multipart file uploads.
|
104
116
|
* Introduced a new Tempfile type.
|
105
117
|
|
106
|
-
|
107
|
-
|
118
|
+
|
119
|
+
## 2.0.0
|
108
120
|
|
109
121
|
* Added new exception subtypes (load methods return more precise errors now)
|
110
122
|
* Changed ```Attributor::Model``` to be a class instead of module.
|
data/lib/attributor.rb
CHANGED
@@ -14,7 +14,7 @@ module Attributor
|
|
14
14
|
require_relative 'attributor/attribute_resolver'
|
15
15
|
|
16
16
|
require_relative 'attributor/example_mixin'
|
17
|
-
|
17
|
+
|
18
18
|
require_relative 'attributor/extensions/randexp'
|
19
19
|
|
20
20
|
|
@@ -45,16 +45,16 @@ module Attributor
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.humanize_context( context )
|
48
|
-
|
48
|
+
return "" unless context
|
49
49
|
|
50
50
|
if context.kind_of? ::String
|
51
51
|
context = Array(context)
|
52
52
|
end
|
53
53
|
|
54
54
|
unless context.is_a? Enumerable
|
55
|
-
raise "INVALID CONTEXT!!! (got: #{context.inspect})"
|
55
|
+
raise "INVALID CONTEXT!!! (got: #{context.inspect})"
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
begin
|
59
59
|
return context.join('.')
|
60
60
|
rescue Exception => e
|
@@ -73,10 +73,10 @@ module Attributor
|
|
73
73
|
|
74
74
|
require_relative 'attributor/families/numeric'
|
75
75
|
require_relative 'attributor/families/temporal'
|
76
|
-
|
76
|
+
|
77
77
|
require_relative 'attributor/types/container'
|
78
78
|
require_relative 'attributor/types/object'
|
79
|
-
|
79
|
+
|
80
80
|
require_relative 'attributor/types/bigdecimal'
|
81
81
|
require_relative 'attributor/types/integer'
|
82
82
|
require_relative 'attributor/types/string'
|
@@ -90,7 +90,7 @@ module Attributor
|
|
90
90
|
require_relative 'attributor/types/hash'
|
91
91
|
require_relative 'attributor/types/model'
|
92
92
|
require_relative 'attributor/types/struct'
|
93
|
-
|
93
|
+
|
94
94
|
|
95
95
|
require_relative 'attributor/types/csv'
|
96
96
|
require_relative 'attributor/types/ids'
|
@@ -98,5 +98,6 @@ module Attributor
|
|
98
98
|
# TODO: move these to 'optional types' or 'extra types'... location
|
99
99
|
require_relative 'attributor/types/tempfile'
|
100
100
|
require_relative 'attributor/types/file_upload'
|
101
|
+
require_relative 'attributor/types/uri'
|
101
102
|
|
102
103
|
end
|
data/lib/attributor/attribute.rb
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
module Attributor
|
4
4
|
|
5
5
|
class FakeParent < ::BasicObject
|
6
|
-
|
6
|
+
|
7
7
|
def method_missing(name, *args)
|
8
8
|
::Kernel.warn "Warning, you have tried to access the '#{name}' method of the 'parent' argument of a Proc-defined :default values." +
|
9
9
|
"Those Procs should completely ignore the 'parent' attribute for the moment as it will be set to an " +
|
10
10
|
"instance of a useless class (until the framework can provide such functionality)"
|
11
11
|
nil
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def class
|
15
15
|
FakeParent
|
16
16
|
end
|
@@ -80,7 +80,7 @@ module Attributor
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def dump(value, **opts)
|
83
|
-
type.dump(value, opts)
|
83
|
+
type.dump(value, **opts)
|
84
84
|
end
|
85
85
|
|
86
86
|
|
@@ -98,7 +98,7 @@ module Attributor
|
|
98
98
|
|
99
99
|
TOP_LEVEL_OPTIONS = [ :description, :values, :default, :example, :required, :required_if, :custom_data ]
|
100
100
|
INTERNAL_OPTIONS = [:dsl_compiler,:dsl_compiler_options] # Options we don't want to expose when describing attributes
|
101
|
-
def describe(shallow=true)
|
101
|
+
def describe(shallow=true, example: nil )
|
102
102
|
description = { }
|
103
103
|
# Clone the common options
|
104
104
|
TOP_LEVEL_OPTIONS.each do |option_name|
|
@@ -109,6 +109,7 @@ module Attributor
|
|
109
109
|
if ( ex_def = description.delete(:example) )
|
110
110
|
description[:example_definition] = ex_def
|
111
111
|
end
|
112
|
+
|
112
113
|
special_options = self.options.keys - TOP_LEVEL_OPTIONS - INTERNAL_OPTIONS
|
113
114
|
description[:options] = {} unless special_options.empty?
|
114
115
|
special_options.each do |opt_name|
|
@@ -119,40 +120,55 @@ module Attributor
|
|
119
120
|
description[:options][:reference] = reference.name
|
120
121
|
end
|
121
122
|
|
122
|
-
description[:type] = self.type.describe(shallow)
|
123
|
+
description[:type] = self.type.describe(shallow, example: example )
|
124
|
+
# Move over any example from the type, into the attribute itself
|
125
|
+
if ( ex = description[:type].delete(:example) )
|
126
|
+
description[:example] = self.dump( ex ).to_s
|
127
|
+
end
|
128
|
+
|
123
129
|
description
|
124
130
|
end
|
125
131
|
|
126
132
|
|
133
|
+
def example_from_options(parent, context)
|
134
|
+
val = self.options[:example]
|
135
|
+
generated = case val
|
136
|
+
when ::Regexp
|
137
|
+
val.gen
|
138
|
+
when ::Array
|
139
|
+
# TODO: handle arrays of non native types, i.e. arrays of regexps.... ?
|
140
|
+
val.pick
|
141
|
+
when ::Proc
|
142
|
+
if val.arity == 2
|
143
|
+
val.call(parent, context)
|
144
|
+
elsif val.arity == 1
|
145
|
+
val.call(parent)
|
146
|
+
else
|
147
|
+
val.call
|
148
|
+
end
|
149
|
+
when nil
|
150
|
+
nil
|
151
|
+
else
|
152
|
+
val
|
153
|
+
end
|
154
|
+
self.load( generated, context )
|
155
|
+
end
|
156
|
+
|
127
157
|
def example(context=nil, parent: nil, values:{})
|
128
158
|
raise ArgumentError, "attribute example cannot take a context of type String" if (context.is_a? ::String )
|
129
159
|
if context
|
130
160
|
ctx = Attributor.humanize_context(context)
|
131
161
|
seed, _ = Digest::SHA1.digest(ctx).unpack("QQ")
|
132
162
|
Random.srand(seed)
|
163
|
+
else
|
164
|
+
context = Attributor::DEFAULT_ROOT_CONTEXT
|
133
165
|
end
|
134
166
|
|
135
167
|
if self.options.has_key? :example
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
when ::Array
|
141
|
-
# TODO: handle arrays of non native types, i.e. arrays of regexps.... ?
|
142
|
-
val.pick
|
143
|
-
when ::Proc
|
144
|
-
if val.arity == 2
|
145
|
-
val.call(parent, context)
|
146
|
-
elsif val.arity == 1
|
147
|
-
val.call(parent)
|
148
|
-
else
|
149
|
-
val.call
|
150
|
-
end
|
151
|
-
when nil
|
152
|
-
nil
|
153
|
-
else
|
154
|
-
self.load(val)
|
155
|
-
end
|
168
|
+
loaded = example_from_options(parent, context)
|
169
|
+
errors = self.validate(loaded, context)
|
170
|
+
raise AttributorException, "Error generating example for #{Attributor.humanize_context(context)}. Errors: #{errors.inspect}" if errors.any?
|
171
|
+
loaded
|
156
172
|
else
|
157
173
|
if (option_values = self.options[:values])
|
158
174
|
option_values.pick
|
@@ -100,7 +100,13 @@ module Attributor
|
|
100
100
|
# determine attribute type to use
|
101
101
|
if attr_type.nil?
|
102
102
|
if block_given?
|
103
|
-
attr_type = Attributor::
|
103
|
+
attr_type = if inherited_attribute && inherited_attribute.type < Attributor::Collection
|
104
|
+
# override the reference to be the member_attribute's type for collections
|
105
|
+
opts[:reference] = inherited_attribute.type.member_attribute.type
|
106
|
+
Attributor::Collection.of(Struct)
|
107
|
+
else
|
108
|
+
Attributor::Struct
|
109
|
+
end
|
104
110
|
elsif inherited_attribute
|
105
111
|
attr_type = inherited_attribute.type
|
106
112
|
else
|
data/lib/attributor/type.rb
CHANGED
@@ -10,9 +10,9 @@ module Attributor
|
|
10
10
|
|
11
11
|
|
12
12
|
module ClassMethods
|
13
|
-
|
14
|
-
# Does this type support the generation of subtypes?
|
15
|
-
def constructable?
|
13
|
+
|
14
|
+
# Does this type support the generation of subtypes?
|
15
|
+
def constructable?
|
16
16
|
false
|
17
17
|
end
|
18
18
|
|
@@ -20,7 +20,7 @@ module Attributor
|
|
20
20
|
def load(value,context=Attributor::DEFAULT_ROOT_CONTEXT, **options)
|
21
21
|
return nil if value.nil?
|
22
22
|
unless value.is_a?(self.native_type)
|
23
|
-
raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self
|
23
|
+
raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self
|
24
24
|
end
|
25
25
|
|
26
26
|
value
|
@@ -89,7 +89,7 @@ module Attributor
|
|
89
89
|
|
90
90
|
|
91
91
|
def generate_subcontext(context, subname)
|
92
|
-
context + [subname]
|
92
|
+
context + [subname]
|
93
93
|
end
|
94
94
|
|
95
95
|
def dsl_compiler
|
@@ -105,15 +105,17 @@ module Attributor
|
|
105
105
|
end
|
106
106
|
|
107
107
|
# Default describe for simple types...only their name (stripping the base attributor module)
|
108
|
-
def describe(root=false)
|
108
|
+
def describe(root=false, example: nil)
|
109
109
|
type_name = self.ancestors.find { |k| k.name && !k.name.empty? }.name
|
110
|
-
{
|
110
|
+
hash = {
|
111
111
|
name: type_name.gsub(Attributor::MODULE_PREFIX_REGEX, ''),
|
112
112
|
family: self.family,
|
113
113
|
id: self.id
|
114
114
|
}
|
115
|
+
hash[:example] = example if example
|
116
|
+
hash
|
115
117
|
end
|
116
|
-
|
118
|
+
|
117
119
|
def id
|
118
120
|
return nil if self.name.nil?
|
119
121
|
self.name.gsub('::'.freeze,'-'.freeze)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
module Attributor
|
5
5
|
|
6
|
-
class Collection
|
6
|
+
class Collection < Array
|
7
7
|
include Container
|
8
8
|
|
9
9
|
# @param type [Attributor::Type] optional, defines the type of all collection members
|
@@ -21,14 +21,31 @@ module Attributor
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
@options = {}
|
25
|
+
|
26
|
+
def self.inherited(klass)
|
27
|
+
klass.instance_eval do
|
28
|
+
@options = {}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.options
|
33
|
+
@options
|
34
|
+
end
|
35
|
+
|
36
|
+
|
24
37
|
def self.native_type
|
25
|
-
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.valid_type?(type)
|
42
|
+
type.kind_of?(self) || type.kind_of?(::Enumerable)
|
26
43
|
end
|
27
44
|
|
28
45
|
def self.family
|
29
46
|
'array'
|
30
47
|
end
|
31
|
-
|
48
|
+
|
32
49
|
def self.member_type
|
33
50
|
@member_type ||= Attributor::Object
|
34
51
|
end
|
@@ -51,16 +68,20 @@ module Attributor
|
|
51
68
|
context ||= ["Collection-#{result.object_id}"]
|
52
69
|
context = Array(context)
|
53
70
|
|
71
|
+
# avoid infinite recursion in example generation
|
72
|
+
example_depth = context.size
|
73
|
+
size = 0 if example_depth > Hash::MAX_EXAMPLE_DEPTH
|
74
|
+
|
54
75
|
size.times do |i|
|
55
76
|
subcontext = context + ["at(#{i})"]
|
56
77
|
result << self.member_attribute.example(subcontext)
|
57
78
|
end
|
58
79
|
|
59
|
-
result
|
80
|
+
self.new(result)
|
60
81
|
end
|
61
82
|
|
62
83
|
|
63
|
-
# The incoming value should be
|
84
|
+
# The incoming value should be array-like here, so the only decoding that we need to do
|
64
85
|
# is from the members (if there's an :member_type defined option).
|
65
86
|
def self.load(value,context=Attributor::DEFAULT_ROOT_CONTEXT, **options)
|
66
87
|
if value.nil?
|
@@ -69,11 +90,13 @@ module Attributor
|
|
69
90
|
loaded_value = value
|
70
91
|
elsif value.is_a?(::String)
|
71
92
|
loaded_value = decode_string(value,context)
|
93
|
+
elsif value.respond_to?(:to_a)
|
94
|
+
loaded_value = value.to_a
|
72
95
|
else
|
73
96
|
raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self
|
74
97
|
end
|
75
98
|
|
76
|
-
|
99
|
+
self.new(loaded_value.collect { |member| self.member_attribute.load(member,context) })
|
77
100
|
end
|
78
101
|
|
79
102
|
|
@@ -87,20 +110,21 @@ module Attributor
|
|
87
110
|
values.collect { |value| member_attribute.dump(value,opts) }
|
88
111
|
end
|
89
112
|
|
90
|
-
def self.describe(shallow=false)
|
113
|
+
def self.describe(shallow=false, example: nil)
|
91
114
|
hash = super(shallow)
|
92
115
|
hash[:options] = {} unless hash[:options]
|
93
|
-
|
116
|
+
member_example = example.first if example
|
117
|
+
hash[:member_attribute] = self.member_attribute.describe(true, example: member_example )
|
94
118
|
hash
|
95
119
|
end
|
96
120
|
|
97
121
|
|
98
|
-
def self.constructable?
|
122
|
+
def self.constructable?
|
99
123
|
true
|
100
124
|
end
|
101
125
|
|
102
|
-
def self.construct(constructor_block, options)
|
103
126
|
|
127
|
+
def self.construct(constructor_block, options)
|
104
128
|
member_options = (options[:member_options] || {} ).clone
|
105
129
|
if options.has_key?(:reference) && !member_options.has_key?(:reference)
|
106
130
|
member_options[:reference] = options[:reference]
|
@@ -131,6 +155,16 @@ module Attributor
|
|
131
155
|
|
132
156
|
# @param values [Array] Array of values to validate
|
133
157
|
def self.validate(values, context=Attributor::DEFAULT_ROOT_CONTEXT, attribute=nil)
|
158
|
+
|
159
|
+
unless self.valid_type?(values)
|
160
|
+
descriptive_type =if self.member_type != Object
|
161
|
+
"Collection.of(#{self.member_type})"
|
162
|
+
else
|
163
|
+
self
|
164
|
+
end
|
165
|
+
raise Attributor::IncompatibleTypeError, context: context, value_type: values.class, type: descriptive_type
|
166
|
+
end
|
167
|
+
|
134
168
|
values.each_with_index.collect do |value, i|
|
135
169
|
subcontext = context + ["at(#{i})"]
|
136
170
|
self.member_attribute.validate(value, subcontext)
|
@@ -142,5 +176,10 @@ module Attributor
|
|
142
176
|
errors
|
143
177
|
end
|
144
178
|
|
179
|
+
|
180
|
+
def dump(**opts)
|
181
|
+
self.collect { |value| self.class.member_attribute.dump(value,opts) }
|
182
|
+
end
|
183
|
+
|
145
184
|
end
|
146
185
|
end
|