Class: Attributor::Collection
- Inherits:
-
Array
- Object
- Array
- Attributor::Collection
- Defined in:
- lib/attributor/types/collection.rb
Direct Known Subclasses
Class Attribute Summary collapse
-
.options ⇒ Object
readonly
Returns the value of attribute options.
Class Method Summary collapse
- .check_option!(name, _definition) ⇒ Object
- .construct(constructor_block, options) ⇒ Object
- .constructable? ⇒ Boolean
- .decode_string(value, context) ⇒ Object
- .describe(shallow = false, example: nil) ⇒ Object
- .dump(values, **opts) ⇒ Object
-
.example(context = nil, options: {}) ⇒ Object
generates an example Collection TODO: ALLOW to pass “values” for the members?…as values: 1, ….
- .family ⇒ Object
- .inherited(klass) ⇒ Object
-
.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) ⇒ Object
The incoming value should be array-like here, so the only decoding that we need to do is from the members (if there’s an :member_type defined option).
- .member_attribute ⇒ Object
- .member_type ⇒ Object
- .native_type ⇒ Object
-
.of(type) ⇒ Object
Anonymous class with specified type of collection members.
- .valid_type?(type) ⇒ Boolean
- .validate(object, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil) ⇒ Object
- .validate_options(_value, _context, _attribute) ⇒ Object
Instance Method Summary collapse
Methods included from Container
Class Attribute Details
.options ⇒ Object (readonly)
Returns the value of attribute options.
33 34 35 |
# File 'lib/attributor/types/collection.rb', line 33 def @options end |
Class Method Details
.check_option!(name, _definition) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/attributor/types/collection.rb', line 140 def self.check_option!(name, _definition) # TODO: support more options like :max_size case name when :reference when :member_options else return :unknown end :ok end |
.construct(constructor_block, options) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/attributor/types/collection.rb', line 124 def self.construct(constructor_block, ) = ([:member_options] || {}).clone if .key?(:reference) && !.key?(:reference) [:reference] = [:reference] end # create the member_attribute, passing in our member_type and whatever constructor_block is. # that in turn will call construct on the type if applicable. @member_attribute = Attributor::Attribute.new member_type, , &constructor_block # overwrite our type with whatever type comes out of the attribute @member_type = @member_attribute.type self end |
.constructable? ⇒ Boolean
120 121 122 |
# File 'lib/attributor/types/collection.rb', line 120 def self.constructable? true end |
.decode_string(value, context) ⇒ Object
100 101 102 |
# File 'lib/attributor/types/collection.rb', line 100 def self.decode_string(value, context) decode_json(value, context) end |
.describe(shallow = false, example: nil) ⇒ Object
109 110 111 112 113 114 115 116 117 118 |
# File 'lib/attributor/types/collection.rb', line 109 def self.describe(shallow = false, example: nil) hash = super(shallow) hash[:options] = {} unless hash[:options] if example hash[:example] = example member_example = example.first end hash[:member_attribute] = member_attribute.describe(true, example: member_example) hash end |
.dump(values, **opts) ⇒ Object
104 105 106 107 |
# File 'lib/attributor/types/collection.rb', line 104 def self.dump(values, **opts) return nil if values.nil? values.collect { |value| member_attribute.dump(value, opts) } end |
.example(context = nil, options: {}) ⇒ Object
generates an example Collection TODO: ALLOW to pass “values” for the members?…as values: 1, …
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/attributor/types/collection.rb', line 63 def self.example(context = nil, options: {}) result = [] size = [:size] || (rand(3) + 1) size = [*size].sample if size.is_a?(Range) context ||= ["Collection-#{result.object_id}"] context = Array(context) # avoid infinite recursion in example generation example_depth = context.size size = 0 if example_depth > Hash::MAX_EXAMPLE_DEPTH size.times do |i| subcontext = context + ["at(#{i})"] result << member_attribute.example(subcontext) end new(result) end |
.family ⇒ Object
44 45 46 |
# File 'lib/attributor/types/collection.rb', line 44 def self.family 'array' end |
.inherited(klass) ⇒ Object
26 27 28 29 30 |
# File 'lib/attributor/types/collection.rb', line 26 def self.inherited(klass) klass.instance_eval do @options = {} end end |
.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) ⇒ Object
The incoming value should be array-like here, so the only decoding that we need to do is from the members (if there’s an :member_type defined option).
85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/attributor/types/collection.rb', line 85 def self.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **) return nil if value.nil? if value.is_a?(Enumerable) loaded_value = value elsif value.is_a?(::String) loaded_value = decode_string(value, context) elsif value.respond_to?(:to_a) loaded_value = value.to_a else raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self end new(loaded_value.collect { |member| member_attribute.load(member, context) }) end |
.member_attribute ⇒ Object
52 53 54 55 56 57 58 |
# File 'lib/attributor/types/collection.rb', line 52 def self.member_attribute @member_attribute ||= begin construct(nil, {}) @member_attribute end end |
.member_type ⇒ Object
48 49 50 |
# File 'lib/attributor/types/collection.rb', line 48 def self.member_type @member_type ||= Attributor::Object end |
.native_type ⇒ Object
36 37 38 |
# File 'lib/attributor/types/collection.rb', line 36 def self.native_type self end |
.of(type) ⇒ Object
Returns anonymous class with specified type of collection members.
14 15 16 17 18 19 20 21 22 |
# File 'lib/attributor/types/collection.rb', line 14 def self.of(type) resolved_type = Attributor.resolve_type(type) unless resolved_type.ancestors.include?(Attributor::Type) raise Attributor::AttributorException, 'Collections can only have members that are Attributor::Types' end ::Class.new(self) do @member_type = resolved_type end end |
.valid_type?(type) ⇒ Boolean
40 41 42 |
# File 'lib/attributor/types/collection.rb', line 40 def self.valid_type?(type) type.is_a?(self) || type.is_a?(::Enumerable) end |
.validate(object, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil) ⇒ Object
153 154 155 156 157 158 159 160 161 |
# File 'lib/attributor/types/collection.rb', line 153 def self.validate(object, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil) context = [context] if context.is_a? ::String unless object.is_a?(self) raise ArgumentError, "#{name} can not validate object of type #{object.class.name} for #{Attributor.humanize_context(context)}." end object.validate(context) end |
.validate_options(_value, _context, _attribute) ⇒ Object
163 164 165 166 |
# File 'lib/attributor/types/collection.rb', line 163 def self.(_value, _context, _attribute) errors = [] errors end |
Instance Method Details
#dump(**opts) ⇒ Object
175 176 177 |
# File 'lib/attributor/types/collection.rb', line 175 def dump(**opts) collect { |value| self.class.member_attribute.dump(value, opts) } end |
#validate(context = Attributor::DEFAULT_ROOT_CONTEXT) ⇒ Object
168 169 170 171 172 173 |
# File 'lib/attributor/types/collection.rb', line 168 def validate(context = Attributor::DEFAULT_ROOT_CONTEXT) each_with_index.collect do |value, i| subcontext = context + ["at(#{i})"] self.class.member_attribute.validate(value, subcontext) end.flatten.compact end |