class JDDF::Validator::VM

VM

Attributes

errors[RW]
instance_tokens[RW]
max_depth[RW]
max_errors[RW]
root_schema[RW]
schema_tokens[RW]

Public Instance Methods

pop_instance_token() click to toggle source
# File lib/jddf/validator.rb, line 238
def pop_instance_token
  instance_tokens.pop
end
pop_schema_token() click to toggle source
# File lib/jddf/validator.rb, line 246
def pop_schema_token
  schema_tokens.last.pop
end
push_error() click to toggle source
# File lib/jddf/validator.rb, line 250
def push_error
  error = ValidationError.new
  error.instance_path = instance_tokens.clone
  error.schema_path = schema_tokens.last.clone

  errors << error

  raise MaxErrorsError if errors.size == max_errors
end
push_instance_token(token) click to toggle source
# File lib/jddf/validator.rb, line 234
def push_instance_token(token)
  instance_tokens << token
end
push_schema_token(token) click to toggle source
# File lib/jddf/validator.rb, line 242
def push_schema_token(token)
  schema_tokens.last << token
end
validate(schema, instance, parent_tag = nil) click to toggle source
# File lib/jddf/validator.rb, line 45
def validate(schema, instance, parent_tag = nil)
  case schema.form
  when :ref
    raise MaxDepthExceededError if schema_tokens.size == max_depth

    schema_tokens << ['definitions', schema.ref]
    validate(root_schema.definitions[schema.ref], instance)
    schema_tokens.pop
  when :type
    push_schema_token('type')

    case schema.type
    when :boolean
      push_error if instance != true && instance != false
    when :float32, :float64
      push_error unless instance.is_a?(Numeric)
    when :int8
      validate_int(instance, -128, 127)
    when :uint8
      validate_int(instance, 0, 255)
    when :int16
      validate_int(instance, -32_768, 32_767)
    when :uint16
      validate_int(instance, 0, 65_535)
    when :int32
      validate_int(instance, -2_147_483_648, 2_147_483_647)
    when :uint32
      validate_int(instance, 0, 4_294_967_295)
    when :string
      push_error unless instance.is_a?(String)
    when :timestamp
      begin
        DateTime.rfc3339(instance)
      rescue TypeError, ArgumentError
        push_error
      end
    end

    pop_schema_token
  when :enum
    push_schema_token('enum')
    push_error unless schema.enum.include?(instance)
    pop_schema_token
  when :elements
    push_schema_token('elements')

    if instance.is_a?(Array)
      instance.each_with_index do |sub_instance, index|
        push_instance_token(index.to_s)
        validate(schema.elements, sub_instance)
        pop_instance_token
      end
    else
      push_error
    end

    pop_schema_token
  when :properties
    if instance.is_a?(Hash)
      if schema.properties
        push_schema_token('properties')

        schema.properties.each do |key, sub_schema|
          push_schema_token(key)

          if instance.include?(key)
            push_instance_token(key)
            validate(sub_schema, instance[key])
            pop_instance_token
          else
            push_error
          end

          pop_schema_token
        end

        pop_schema_token
      end

      if schema.optional_properties
        push_schema_token('optionalProperties')

        schema.optional_properties.each do |key, sub_schema|
          push_schema_token(key)

          if instance.include?(key)
            push_instance_token(key)
            validate(sub_schema, instance[key])
            pop_instance_token
          end

          pop_schema_token
        end

        pop_schema_token
      end

      unless schema.additional_properties
        instance.keys.each do |key|
          in_properties =
            schema.properties&.include?(key)
          in_optional_properties =
            schema.optional_properties&.include?(key)
          is_parent_tag = parent_tag == key

          unless in_properties || in_optional_properties || is_parent_tag
            push_instance_token(key)
            push_error
            pop_instance_token
          end
        end
      end
    else
      if schema.properties.nil?
        push_schema_token('optionalProperties')
      else
        push_schema_token('properties')
      end

      push_error
      pop_schema_token
    end
  when :values
    push_schema_token('values')

    if instance.is_a?(Hash)
      instance.each do |key, value|
        push_instance_token(key)
        validate(schema.values, value)
        pop_instance_token
      end
    else
      push_error
    end

    pop_schema_token
  when :discriminator
    push_schema_token('discriminator')

    if instance.is_a?(Hash)
      if instance.include?(schema.discriminator.tag)
        tag_value = instance[schema.discriminator.tag]

        if tag_value.is_a?(String)
          push_schema_token('mapping')

          if schema.discriminator.mapping.include?(tag_value)
            sub_schema = schema.discriminator.mapping[tag_value]

            push_schema_token(tag_value)
            validate(sub_schema, instance, schema.discriminator.tag)
            pop_schema_token
          else
            push_instance_token(schema.discriminator.tag)
            push_error
            pop_instance_token
          end

          pop_schema_token
        else
          push_instance_token(schema.discriminator.tag)
          push_schema_token('tag')
          push_error
          pop_schema_token
          pop_instance_token
        end
      else
        push_schema_token('tag')
        push_error
        pop_schema_token
      end
    else
      push_error
    end

    pop_schema_token
  end
end
validate_int(instance, min, max) click to toggle source
# File lib/jddf/validator.rb, line 224
def validate_int(instance, min, max)
  if instance.is_a?(Numeric)
    if instance.modulo(1).nonzero? || instance < min || instance > max
      push_error
    end
  else
    push_error
  end
end