class Hoodoo::Presenters::Array
A JSON Array
schema member.
Attributes
The properties of this object, an array
of Field
instances.
Public Class Methods
Initialize an Array
instance with the appropriate name and options.
name
-
The JSON key.
options
-
A
Hash
of options, e.g.:required => true, :type => :enum, :field_from => [ 1, 2, 3, 4 ]
. If a:type
field is present, theArray
contains atomic types of the given kind. Otherwise, either pass a block with inner schema DSL calls describing complex array entry schema, or nothing for no array content validation. If a block and:type
option are passed, the block is used and option ignored.
Hoodoo::Presenters::Field::new
# File lib/hoodoo/presenters/types/array.rb, line 26 def initialize( name, options = {} ) super( name, options ) if options.has_key?( :type ) # Defining a property via "#property" adds it to the @properties # array, but handling of simple Types in array validation and # rendering is too different from complex types to use the same # code flow; we need the property to be independently used, so # extract it into its own instance variable and delete the item # from @properties. # value_klass = type_option_to_class( options[ :type ] ) random_name = Hoodoo::UUID.generate() @value_property = property( random_name, value_klass, extract_field_prefix_options_from( options ) ) @properties.delete( random_name ) # This is approaching a blunt hack. Without it, validation errors # will result in e.g. "fields[1].cd2f0a15ec8e4bd6ab1964b25b044e69" # in error messages. By using nil, the validation code's JSON path # array to string code doesn't include the item, giving the # desired result. In addition, the base class Field#render code # has an important check for non-nil but empty and bails out, but # allows the nil name case to render simple types as expected. A # delicate / fragile balance of nil-vs-empty arises. # @value_property.name = nil end end
Public Instance Methods
Render an array into the target hash based on the internal state that describes this instance’s current path (position in the heirarchy of nested schema entities).
data
-
The
Array
to render. target
-
The
Hash
that we render into. A “path” of keys leading to nested Hashes is built via +super()+, with the final key entry yielding the rendered array.
Hoodoo::Presenters::Field#render
# File lib/hoodoo/presenters/types/array.rb, line 107 def render( data, target ) # Data provided is explicitly nil or not an array? Don't need to render # anything beyond 'nil' at the field (the not-array case covers nil and # covers invalid input, which is treated as nil). return super( nil, target ) if ! data.is_a?( ::Array ) # Otherwise, start looking at rendering array contents (even if the # input array is empty). This relies on pass-by-reference; we'll update # this specific instance of 'array' later. Call 'super' to render the # 'array' instance in place in 'target' straight away... array = [] path = super( array, target ) # ...then look at rendering the input entries of 'data' into 'array'. if @properties.nil? == false && @properties.empty? == false data.each do | item | # We have properties defined so array values (in "item") must be # Hashes. If non-Hash, treat as if nil; explicit-nil-means-nil. unless item.is_a?( ::Hash ) # Must modify existing instance of 'array', so use 'push()' array.push( nil ) next end subtarget = {} @properties.each do | name, property | name = name.to_s has_key = item.has_key?( name ) next unless has_key || property.has_default?() property.render( has_key ? item[ name ] : property.default, subtarget ) end rendered = subtarget.empty? ? {} : read_at_path( subtarget, path ) # Must modify existing instance of 'array', so use 'push()' array.push( rendered ) end elsif @value_property.nil? == false data.each do | item | subtarget = {} @value_property.render( item, subtarget ) rendered = subtarget.empty? ? nil : read_at_path( subtarget, path ).values.first # Must modify existing instance of 'array', so use 'push()' array.push( rendered ) end else # Must modify existing instance of 'array', so use 'push()' array.push( *data ) end end
Check if data is a valid Array
and return a Hoodoo::Errors
instance.
Hoodoo::Presenters::Field#validate
# File lib/hoodoo/presenters/types/array.rb, line 62 def validate( data, path = '' ) errors = super( data, path ) return errors if errors.has_errors? || ( ! @required && data.nil? ) if data.is_a?( ::Array ) # A block which defined properties for this instance takes # precedence; then check for a ":type" option via "@@value_property" # stored in the constructor; then give up and do no validation. # if @properties.nil? == false && @properties.empty? == false data.each_with_index do | item, index | @properties.each do | name, property | rdata = ( item.is_a?( ::Hash ) && item.has_key?( name ) ) ? item[ name ] : nil indexed_path = "#{ full_path( path ) }[#{ index }]" errors.merge!( property.validate( rdata, indexed_path ) ) end end elsif @value_property.nil? == false data.each_with_index do | item, index | indexed_path = "#{ full_path( path ) }[#{ index }]" errors.merge!( @value_property.validate( item, indexed_path ) ) end end else errors.add_error( 'generic.invalid_array', :message => "Field `#{ full_path( path ) }` is an invalid array", :reference => { :field_name => full_path( path ) } ) end errors end
Invoke a given block, passing this item; call recursively for any defined sub-fields too. See Hoodoo::Presenters::Base#walk for why.
- &block
-
Mandatory block, which is passed ‘self’ when called.
# File lib/hoodoo/presenters/types/array.rb, line 176 def walk( &block ) block.call( self ) @properties.each do | name, property | property.walk( &block ) end unless @properties.nil? end