class JSON::Validator

Public Class Methods

add_schema(schema) click to toggle source
# File lib/json-schema/validator.rb, line 305
def add_schema(schema)
  @@schemas[schema_key_for(schema.uri)] ||= schema
end
cache_schemas=(val) click to toggle source
# File lib/json-schema/validator.rb, line 324
def cache_schemas=(val)
  warn "[DEPRECATION NOTICE] Schema caching is now a validation option. Schemas will still be cached if this is set to true, but this method will be removed in version >= 3. Please use the :clear_cache validation option instead."
  @@cache_schemas = val == true ? true : false
end
clear_cache() click to toggle source
# File lib/json-schema/validator.rb, line 296
def clear_cache
  @@schemas = {}
  JSON::Util::URI.clear_cache
end
default_validator() click to toggle source
# File lib/json-schema/validator.rb, line 333
def default_validator
  @@default_validator
end
deregister_format_validator(format, versions = (@@validators.flat_map{ |k, v| v.names.first } + [nil])) click to toggle source
# File lib/json-schema/validator.rb, line 382
def deregister_format_validator(format, versions = (@@validators.flat_map{ |k, v| v.names.first } + [nil]))
  versions.each do |version|
    validator = validator_for_name(version)
    validator.formats[format.to_s] = validator.default_formats[format.to_s]
  end
end
fully_validate(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 270
def fully_validate(schema, data, opts={})
  validate!(schema, data, opts.merge(:record_errors => true))
end
fully_validate_json(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 280
def fully_validate_json(schema, data, opts={})
  fully_validate(schema, data, opts.merge(:json => true))
end
fully_validate_schema(schema, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 274
def fully_validate_schema(schema, opts={})
  data = schema
  schema = validator_for_name(opts[:version]).metaschema
  fully_validate(schema, data, opts)
end
fully_validate_uri(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 284
def fully_validate_uri(schema, data, opts={})
  fully_validate(schema, data, opts.merge(:uri => true))
end
json_backend() click to toggle source
# File lib/json-schema/validator.rb, line 396
def json_backend
  if defined?(MultiJson)
    MultiJson.respond_to?(:adapter) ? MultiJson.adapter : MultiJson.engine
  else
    @@json_backend
  end
end
json_backend=(backend) click to toggle source
# File lib/json-schema/validator.rb, line 404
def json_backend=(backend)
  if defined?(MultiJson)
    backend = backend == 'json' ? 'json_gem' : backend
    MultiJson.respond_to?(:use) ? MultiJson.use(backend) : MultiJson.engine = backend
  else
    backend = backend.to_s
    if @@available_json_backends.include?(backend)
      @@json_backend = backend
    else
      raise JSON::Schema::JsonParseError.new("The JSON backend '#{backend}' could not be found.")
    end
  end
end
merge_missing_values(source, destination) click to toggle source
# File lib/json-schema/validator.rb, line 447
def merge_missing_values(source, destination)
  case destination
  when Hash
    source.each do |key, source_value|
      destination_value = destination[key] || destination[key.to_sym]
      if destination_value.nil?
        destination[key] = source_value
      else
        merge_missing_values(source_value, destination_value)
      end
    end
  when Array
    source.each_with_index do |source_value, i|
      destination_value = destination[i]
      merge_missing_values(source_value, destination_value)
    end
  end
end
new(schema_data, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 40
def initialize(schema_data, data, opts={})
  @options = @@default_opts.clone.merge(opts)
  @errors = []

  validator = self.class.validator_for_name(@options[:version])
  @options[:version] = validator
  @options[:schema_reader] ||= self.class.schema_reader

  @validation_options = @options[:record_errors] ? {:record_errors => true} : {}
  @validation_options[:insert_defaults] = true if @options[:insert_defaults]
  @validation_options[:strict] = true if @options[:strict] == true
  @validation_options[:clear_cache] = true if !@@cache_schemas || @options[:clear_cache]

  @@mutex.synchronize { @base_schema = initialize_schema(schema_data) }
  @original_data = data
  @data = initialize_data(data)
  @@mutex.synchronize { build_schemas(@base_schema) }

  # validate the schema, if requested
  if @options[:validate_schema]
    if @base_schema.schema["$schema"]
      base_validator = self.class.validator_for_name(@base_schema.schema["$schema"])
    end
    metaschema = base_validator ? base_validator.metaschema : validator.metaschema
    # Don't clear the cache during metaschema validation!
    self.class.validate!(metaschema, @base_schema.schema, {:clear_cache => false})
  end

  # If the :fragment option is set, try and validate against the fragment
  if opts[:fragment]
    @base_schema = schema_from_fragment(@base_schema, opts[:fragment])
  end
end
parse(s) click to toggle source
# File lib/json-schema/validator.rb, line 418
def parse(s)
  if defined?(MultiJson)
    begin
      MultiJson.respond_to?(:adapter) ? MultiJson.load(s) : MultiJson.decode(s)
    rescue MultiJson::ParseError => e
      raise JSON::Schema::JsonParseError.new(e.message)
    end
  else
    case @@json_backend.to_s
    when 'json'
      begin
        JSON.parse(s, :quirks_mode => true)
      rescue JSON::ParserError => e
        raise JSON::Schema::JsonParseError.new(e.message)
      end
    when 'yajl'
      begin
        json = StringIO.new(s)
        parser = Yajl::Parser.new
        parser.parse(json) or raise JSON::Schema::JsonParseError.new("The JSON could not be parsed by yajl")
      rescue Yajl::ParseError => e
        raise JSON::Schema::JsonParseError.new(e.message)
      end
    else
      raise JSON::Schema::JsonParseError.new("No supported JSON parsers found. The following parsers are suported:\n * yajl-ruby\n * json")
    end
  end
end
register_default_validator(v) click to toggle source
# File lib/json-schema/validator.rb, line 370
def register_default_validator(v)
  @@default_validator = v
end
register_format_validator(format, validation_proc, versions = (@@validators.flat_map{ |k, v| v.names.first } + [nil])) click to toggle source
# File lib/json-schema/validator.rb, line 374
def register_format_validator(format, validation_proc, versions = (@@validators.flat_map{ |k, v| v.names.first } + [nil]))
  custom_format_validator = JSON::Schema::CustomFormat.new(validation_proc)
  versions.each do |version|
    validator = validator_for_name(version)
    validator.formats[format.to_s] = custom_format_validator
  end
end
register_validator(v) click to toggle source
# File lib/json-schema/validator.rb, line 366
def register_validator(v)
  @@validators["#{v.uri.scheme}://#{v.uri.host}#{v.uri.path}"] = v
end
restore_default_formats(versions = (@@validators.flat_map{ |k, v| v.names.first } + [nil])) click to toggle source
# File lib/json-schema/validator.rb, line 389
def restore_default_formats(versions = (@@validators.flat_map{ |k, v| v.names.first } + [nil]))
  versions.each do |version|
    validator = validator_for_name(version)
    validator.formats = validator.default_formats.clone
  end
end
schema_for_uri(uri) click to toggle source
# File lib/json-schema/validator.rb, line 309
def schema_for_uri(uri)
  # We only store normalized uris terminated with fragment #, so we can try whether
  # normalization can be skipped
  @@schemas[uri] || @@schemas[schema_key_for(uri)]
end
schema_key_for(uri) click to toggle source
# File lib/json-schema/validator.rb, line 319
def schema_key_for(uri)
  key = Util::URI.normalized_uri(uri).to_s
  key.end_with?('#') ? key : "#{key}#"
end
schema_loaded?(schema_uri) click to toggle source
# File lib/json-schema/validator.rb, line 315
def schema_loaded?(schema_uri)
  !schema_for_uri(schema_uri).nil?
end
schema_reader() click to toggle source
# File lib/json-schema/validator.rb, line 288
def schema_reader
  @@schema_reader ||= JSON::Schema::Reader.new
end
schema_reader=(reader) click to toggle source
# File lib/json-schema/validator.rb, line 292
def schema_reader=(reader)
  @@schema_reader = reader
end
schemas() click to toggle source
# File lib/json-schema/validator.rb, line 301
def schemas
  @@schemas
end
validate(schema, data,opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 236
def validate(schema, data,opts={})
  begin
    validate!(schema, data, opts)
  rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
    return false
  end
end
validate!(schema, data,opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 252
def validate!(schema, data,opts={})
  validator = new(schema, data, opts)
  validator.validate
end
validate2(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 257
def validate2(schema, data, opts={})
  warn "[DEPRECATION NOTICE] JSON::Validator#validate2 has been replaced by JSON::Validator#validate! and will be removed in version >= 3. Please use the #validate! method instead."
  validate!(schema, data, opts)
end
validate_json(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 244
def validate_json(schema, data, opts={})
  validate(schema, data, opts.merge(:json => true))
end
validate_json!(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 262
def validate_json!(schema, data, opts={})
  validate!(schema, data, opts.merge(:json => true))
end
validate_uri(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 248
def validate_uri(schema, data, opts={})
  validate(schema, data, opts.merge(:uri => true))
end
validate_uri!(schema, data, opts={}) click to toggle source
# File lib/json-schema/validator.rb, line 266
def validate_uri!(schema, data, opts={})
  validate!(schema, data, opts.merge(:uri => true))
end
validator_for(schema_uri) click to toggle source
# File lib/json-schema/validator.rb, line 361
def validator_for(schema_uri)
  warn "[DEPRECATION NOTICE] JSON::Validator#validator_for has been replaced by JSON::Validator#validator_for_uri and will be removed in version >= 3. Please use the #validator_for_uri method instead."
  validator_for_uri(schema_uri)
end
validator_for_name(schema_name, raise_not_found=true) click to toggle source
# File lib/json-schema/validator.rb, line 348
def validator_for_name(schema_name, raise_not_found=true)
  return default_validator unless schema_name
  schema_name = schema_name.to_s
  validator = validators.values.detect do |v|
    Array(v.names).include?(schema_name)
  end
  if validator.nil? && raise_not_found
    raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported")
  else
    validator
  end
end
validator_for_uri(schema_uri, raise_not_found=true) click to toggle source
# File lib/json-schema/validator.rb, line 337
def validator_for_uri(schema_uri, raise_not_found=true)
  return default_validator unless schema_uri
  u = JSON::Util::URI.parse(schema_uri)
  validator = validators["#{u.scheme}://#{u.host}#{u.path}"]
  if validator.nil? && raise_not_found
    raise JSON::Schema::SchemaError.new("Schema not found: #{schema_uri}")
  else
    validator
  end
end
validators() click to toggle source
# File lib/json-schema/validator.rb, line 329
def validators
  @@validators
end

Public Instance Methods

build_schemas(parent_schema) click to toggle source

Build all schemas with IDs, mapping out the namespace

# File lib/json-schema/validator.rb, line 146
def build_schemas(parent_schema)
  schema = parent_schema.schema

  # Build ref schemas if they exist
  if schema["$ref"]
    load_ref_schema(parent_schema, schema["$ref"])
  end

  case schema["extends"]
  when String
    load_ref_schema(parent_schema, schema["extends"])
  when Array
    schema['extends'].each do |type|
      handle_schema(parent_schema, type)
    end
  end

  # Check for schemas in union types
  ["type", "disallow"].each do |key|
    if schema[key].is_a?(Array)
      schema[key].each do |type|
        if type.is_a?(Hash)
          handle_schema(parent_schema, type)
        end
      end
    end
  end

  # Schema properties whose values are objects, the values of which
  # are themselves schemas.
  %w[definitions properties patternProperties].each do |key|
    next unless value = schema[key]
    value.each do |k, inner_schema|
      handle_schema(parent_schema, inner_schema)
    end
  end

  # Schema properties whose values are themselves schemas.
  %w[additionalProperties additionalItems dependencies extends].each do |key|
    next unless schema[key].is_a?(Hash)
    handle_schema(parent_schema, schema[key])
  end

  # Schema properties whose values may be an array of schemas.
  %w[allOf anyOf oneOf not].each do |key|
    next unless value = schema[key]
    Array(value).each do |inner_schema|
      handle_schema(parent_schema, inner_schema)
    end
  end

  # Items are always schemas
  if schema["items"]
    items = schema["items"].clone
    items = [items] unless items.is_a?(Array)

    items.each do |item|
      handle_schema(parent_schema, item)
    end
  end

  # Convert enum to a ArraySet
  if schema["enum"].is_a?(Array)
    schema["enum"] = ArraySet.new(schema["enum"])
  end

end
handle_schema(parent_schema, obj) click to toggle source

Either load a reference schema or create a new schema

# File lib/json-schema/validator.rb, line 215
def handle_schema(parent_schema, obj)
  if obj.is_a?(Hash)
    schema_uri = parent_schema.uri.dup
    schema = JSON::Schema.new(obj, schema_uri, parent_schema.validator)
    if obj['id']
      self.class.add_schema(schema)
    end
    build_schemas(schema)
  end
end
load_ref_schema(parent_schema, ref) click to toggle source
# File lib/json-schema/validator.rb, line 133
def load_ref_schema(parent_schema, ref)
  schema_uri = JSON::Util::URI.absolutize_ref(ref, parent_schema.uri)
  return true if self.class.schema_loaded?(schema_uri)

  validator = self.class.validator_for_uri(schema_uri, false)
  schema_uri = JSON::Util::URI.file_uri(validator.metaschema) if validator

  schema = @options[:schema_reader].read(schema_uri)
  self.class.add_schema(schema)
  build_schemas(schema)
end
schema_from_fragment(base_schema, fragment) click to toggle source
# File lib/json-schema/validator.rb, line 74
def schema_from_fragment(base_schema, fragment)
  schema_uri = base_schema.uri
  fragments = fragment.split("/")

  # ensure the first element was a hash, per the fragment spec
  if fragments.shift != "#"
    raise JSON::Schema::SchemaError.new("Invalid fragment syntax in :fragment option")
  end

  fragments.each do |f|
    if base_schema.is_a?(JSON::Schema) #test if fragment is a JSON:Schema instance
      if !base_schema.schema.has_key?(f)
        raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
      end
      base_schema = base_schema.schema[f]
    elsif base_schema.is_a?(Hash)
      if !base_schema.has_key?(f)
        raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
      end
      base_schema = JSON::Schema.new(base_schema[f],schema_uri,@options[:version])
    elsif base_schema.is_a?(Array)
      if base_schema[f.to_i].nil?
        raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
      end
      base_schema = JSON::Schema.new(base_schema[f.to_i],schema_uri,@options[:version])
    else
      raise JSON::Schema::SchemaError.new("Invalid schema encountered when resolving :fragment option")
    end
  end

  if @options[:list]
    base_schema.to_array_schema
  else
    base_schema
  end
end
validate() click to toggle source

Run a simple true/false validation of data against a schema

# File lib/json-schema/validator.rb, line 112
def validate
  @base_schema.validate(@data,[],self,@validation_options)

  if @options[:record_errors]
    if @options[:errors_as_objects]
      @errors.map{|e| e.to_hash}
    else
      @errors.map{|e| e.to_string}
    end
  else
    true
  end
ensure
  if @validation_options[:clear_cache] == true
    self.class.clear_cache
  end
  if @validation_options[:insert_defaults]
    self.class.merge_missing_values(@data, @original_data)
  end
end
validation_error(error) click to toggle source
# File lib/json-schema/validator.rb, line 226
def validation_error(error)
  @errors.push(error)
end
validation_errors() click to toggle source
# File lib/json-schema/validator.rb, line 230
def validation_errors
  @errors
end

Private Instance Methods

custom_open(uri) click to toggle source
# File lib/json-schema/validator.rb, line 590
def custom_open(uri)
  uri = Util::URI.normalized_uri(uri) if uri.is_a?(String)
  if uri.absolute? && Util::URI::SUPPORTED_PROTOCOLS.include?(uri.scheme)
    begin
      open(uri.to_s).read
    rescue OpenURI::HTTPError, Timeout::Error => e
      raise JSON::Schema::JsonLoadError, e.message
    end
  else
    begin
      File.read(JSON::Util::URI.unescaped_path(uri))
    rescue SystemCallError => e
      raise JSON::Schema::JsonLoadError, e.message
    end
  end
end
fake_uuid(schema) click to toggle source
# File lib/json-schema/validator.rb, line 516
def fake_uuid schema
  @@fake_uuid_generator.call(schema)
end
initialize_data(data) click to toggle source
# File lib/json-schema/validator.rb, line 567
def initialize_data(data)
  if @options[:parse_data]
    if @options[:json]
      data = self.class.parse(data)
    elsif @options[:uri]
      json_uri = Util::URI.normalized_uri(data)
      data = self.class.parse(custom_open(json_uri))
    elsif data.is_a?(String)
      begin
        data = self.class.parse(data)
      rescue JSON::Schema::JsonParseError
        begin
          json_uri = Util::URI.normalized_uri(data)
          data = self.class.parse(custom_open(json_uri))
        rescue JSON::Schema::JsonLoadError
          # Silently discard the error - use the data as-is
        end
      end
    end
  end
  JSON::Schema.stringify(data)
end
initialize_schema(schema) click to toggle source
# File lib/json-schema/validator.rb, line 520
def initialize_schema(schema)
  if schema.is_a?(String)
    begin
      # Build a fake URI for this
      schema_uri = JSON::Util::URI.parse(fake_uuid(schema))
      schema = JSON::Schema.new(self.class.parse(schema), schema_uri, @options[:version])
      if @options[:list] && @options[:fragment].nil?
        schema = schema.to_array_schema
      end
      self.class.add_schema(schema)
    rescue JSON::Schema::JsonParseError
      # Build a uri for it
      schema_uri = Util::URI.normalized_uri(schema)
      if !self.class.schema_loaded?(schema_uri)
        schema = @options[:schema_reader].read(schema_uri)
        schema = JSON::Schema.stringify(schema)

        if @options[:list] && @options[:fragment].nil?
          schema = schema.to_array_schema
        end

        self.class.add_schema(schema)
      else
        schema = self.class.schema_for_uri(schema_uri)
        if @options[:list] && @options[:fragment].nil?
          schema = schema.to_array_schema
          schema.uri = JSON::Util::URI.parse(fake_uuid(serialize(schema.schema)))
          self.class.add_schema(schema)
        end
        schema
      end
    end
  elsif schema.is_a?(Hash)
    schema_uri = JSON::Util::URI.parse(fake_uuid(serialize(schema)))
    schema = JSON::Schema.stringify(schema)
    schema = JSON::Schema.new(schema, schema_uri, @options[:version])
    if @options[:list] && @options[:fragment].nil?
      schema = schema.to_array_schema
    end
    self.class.add_schema(schema)
  else
    raise JSON::Schema::SchemaParseError, "Invalid schema - must be either a string or a hash"
  end

  schema
end
serialize(schema) click to toggle source
# File lib/json-schema/validator.rb, line 508
def serialize schema
  if defined?(MultiJson)
    MultiJson.respond_to?(:dump) ? MultiJson.dump(schema) : MultiJson.encode(schema)
  else
    @@serializer.call(schema)
  end
end