class MinimumTerm::Compare::JsonSchema

Constants

ERRORS

Attributes

errors[R]

Public Class Methods

new(containing_schema) click to toggle source
# File lib/minimum-term/compare/json_schema.rb, line 17
def initialize(containing_schema)
  @containing_schema = containing_schema
end

Public Instance Methods

contains?(contained_schema, pry = false) click to toggle source
# File lib/minimum-term/compare/json_schema.rb, line 21
def contains?(contained_schema, pry = false)
  @errors = []
  @contained_schema = contained_schema
  definitions_contained?
end

Private Instance Methods

_e(error, location, extra = nil) click to toggle source
# File lib/minimum-term/compare/json_schema.rb, line 38
def _e(error, location, extra = nil)
  message = [ERRORS[error], extra].compact.join(": ")
  @errors.push(error: error, message: message, location: location.join("/"))
  false
end
definitions_contained?() click to toggle source
# File lib/minimum-term/compare/json_schema.rb, line 29
def definitions_contained?
  @contained_schema['definitions'].each do |property, contained_property|
    containing_property = @containing_schema['definitions'][property]
    return _e(:ERR_MISSING_DEFINITION, [property]) unless containing_property
    return false unless schema_contains?(containing_property, contained_property, [property])
  end
  true
end
resolve_pointer(pointer, schema) click to toggle source
# File lib/minimum-term/compare/json_schema.rb, line 116
def resolve_pointer(pointer, schema)
  type = pointer[/\#\/definitions\/([^\/]+)$/, 1]
  return false unless type
  schema['definitions'][type]
end
schema_contains?(publish, consume, location = []) click to toggle source
# File lib/minimum-term/compare/json_schema.rb, line 44
def schema_contains?(publish, consume, location = [])

  # We can only compare types and $refs, so let's make
  # sure they're there
  return _e!(:ERR_MISSING_TYPE_AND_REF) unless
    (consume['type'] or consume['$ref']) and
    (publish['type'] or publish['$ref'])

  # There's four possibilities here:
  #
  # 1) publish and consume have a type defined
  # 2) publish and consume have a $ref defined
  # 3) publish has a $ref defined, and consume an inline object
  # 4) consume has a $ref defined, and publish an inline object
  #    (we don't support this yet, as otherwise couldn't check for
  #    missing definitions, because we could never know if something
  #    specified in the definitions of the consuming schema exists in
  #    the publishing schema as an inline property somewhere).
  #    TODO: check if what I just said makes sense. I'm not sure anymore.
  # Let's go:

  # 1)
  if (consume['type'] and publish['type'])
    if consume['type'] != publish['type']
      return _e(:ERR_TYPE_MISMATCH, location, "#{consume['type']} != #{publish['type']}")
    end

  # 2)
  elsif(consume['$ref'] and publish['$ref'])
   resolved_consume = resolve_pointer(consume['$ref'], @contained_schema)
   resolved_publish = resolve_pointer(publish['$ref'], @containing_schema)
   return schema_contains?(resolved_publish, resolved_consume, location)

  # 3)
  elsif(consume['type'] and publish['$ref'])
    if resolved_ref = resolve_pointer(publish['$ref'], @containing_schema)
      return schema_contains?(resolved_ref, consume, location)
    else
      return _e(:ERR_MISSING_POINTER, location, publish['$ref'])
    end

  # 4)
  elsif(consume['$ref'] and publish['type'])
    return _e(:ERR_NOT_SUPPORTED, location)
  end

  # Make sure required properties in consume are required in publish
  consume_required = consume['required'] || []
  publish_required = publish['required'] || []
  missing = (consume_required - publish_required)
  return _e(:ERR_MISSING_REQUIRED, location, missing.to_json) unless missing.empty?

  # We already know that publish and consume's type are equal
  # but if they're objects, we need to do some recursion
  if consume['type'] == 'object'
    consume['properties'].each do |property, schema|
      return _e(:ERR_MISSING_PROPERTY, location, property) unless publish['properties'][property]
      return false unless schema_contains?(publish['properties'][property], schema, location + [property])
    end
  end

  if consume['type'] == 'array'
    sorted_publish = publish['items'].sort
    consume['items'].sort.each_with_index do |item, i|
      next if schema_contains?(sorted_publish[i], item)
      return _e(:ERR_ARRAY_ITEM_MISMATCH, location)
    end
  end

  true
end