class Origami::Array
def self.of(klass, *klasses, length: nil)
Example: Array.of(Integer)
Parameterized Array class with additional typing information.
def self.of(klass, *klasses, length: nil) Class.new(self) do const_set('ARRAY_TYPE', (klasses.empty? and not klass.is_a?(::Array)) ? klass : [ klass ].concat(klasses)) const_set('STATIC_LENGTH', length) def initialize(data = [], parser = nil) super(data, parser, hint_type: self.class.const_get('ARRAY_TYPE')) end def pre_build #:nodoc: do_type_check if Origami::OPTIONS[:enable_type_checking] super end def self.parse(stream, parser = nil) super(stream, parser, hint_type: const_get('ARRAY_TYPE')) end def do_type_check #:nodoc: static_length = self.class.const_get('STATIC_LENGTH') array_type = self.class.const_get('ARRAY_TYPE') if static_length and self.length != static_length STDERR.puts "Warning: object #{self.class.name} has unexpected length #{self.length} (should be #{static_length})" end self.each_with_index do |object, index| index_type = array_type.is_a?(::Array) ? array_type[index % array_type.size] : array_type begin object_value = object.solve rescue InvalidReferenceError STDERR.puts "Warning: in object #{self.class}, invalid reference at index #{index}" next end valid_type = case index_type when Class object_value.is_a?(index_type) when Array index_type.any? { |type| object_value.is_a?(type) } else true end unless valid_type allowed = Array(index_type).map(&:name).join('|') STDERR.puts "Warning: object #{self.class.name} should be one of [#{allowed}] at index #{index} (got #{object_value.type} instead)" end end end end end