lib/json-schema/validator.rb in json-schema-0.1.5 vs lib/json-schema/validator.rb in json-schema-0.1.6

- old
+ new

@@ -3,22 +3,25 @@ require 'pathname' require 'bigdecimal' module JSON - class ValidationError < Exception - attr_reader :fragments, :schema - - def initialize(message, fragments, schema) - @fragments = fragments - @schema = schema - super(message) - end - end - - class Validator + class ValidationError < Exception + attr_reader :fragments, :schema + def initialize(message, fragments, schema) + @fragments = fragments + @schema = schema + super(message) + end + end + + class Validator + + @@schemas = {} + @@cache_schemas = false + ValidationMethods = [ "type", "disallow", "minimum", "maximum", @@ -40,35 +43,42 @@ "$ref" ] def initialize(schema_data, data) - @schemas = {} @base_schema = initialize_schema(schema_data) @data = initialize_data(data) - @schemas[@base_schema.uri.to_s] = @base_schema + Validator.add_schema(@base_schema) build_schemas(@base_schema) end # Run a simple true/false validation of data against a schema def validate() begin validate_schema(@base_schema, @data, []) + Validator.clear_cache return true rescue ValidationError + Validator.clear_cache return false end end # Validate data against a schema, returning nil if the data is valid. If the data is invalid, # a ValidationError will be raised with links to the specific location that the first error # occurred during validation def validate2() - validate_schema(@base_schema, @data, []) + begin + validate_schema(@base_schema, @data, []) + Validator.clear_cache + rescue ValidationError + Validator.clear_cache + raise $! + end nil end # Validate the current schema @@ -451,11 +461,11 @@ end temp_uri.fragment = "" if temp_uri.fragment.nil? # Grab the parent schema from the schema list schema_key = temp_uri.to_s.split("#")[0] - ref_schema = @schemas[schema_key] + ref_schema = Validator.schemas[schema_key] if ref_schema # Perform fragment resolution to retrieve the appropriate level for the schema target_schema = ref_schema.schema fragments = temp_uri.fragment.split("/") @@ -493,14 +503,14 @@ uri.path = (Pathname.new(parent_schema.uri.path).parent + path).cleanpath end uri.fragment = nil end - if @schemas[uri.to_s].nil? + if Validator.schemas[uri.to_s].nil? begin schema = JSON::Schema.new(JSON.parse(open(uri.to_s).read), uri) - @schemas[uri.to_s] = schema + Validator.add_schema(schema) build_schemas(schema) rescue JSON::ParserError # Don't rescue this error, we want JSON formatting issues to bubble up raise $! rescue @@ -511,133 +521,64 @@ end # Build all schemas with IDs, mapping out the namespace def build_schemas(parent_schema) - if parent_schema.schema["type"] && parent_schema.schema["type"].is_a?(Array) # If we're dealing with a Union type, there might be schemas a-brewin' - parent_schema.schema["type"].each_with_index do |type,i| - if type.is_a?(Hash) - if type['$ref'] - load_ref_schema(parent_schema, type['$ref']) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(type,schema_uri) - if type['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) - end - end - end - end - if parent_schema.schema["disallow"] && parent_schema.schema["disallow"].is_a?(Array) # If we're dealing with a Union type, there might be schemas a-brewin' - parent_schema.schema["disallow"].each_with_index do |type,i| - if type.is_a?(Hash) - if type['$ref'] - load_ref_schema(parent_schema, type['$ref']) - else - type['id'] - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(type,schema_uri) - if type['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) + # Check for schemas in union types + ["type", "disallow"].each do |key| + if parent_schema.schema[key] && parent_schema.schema[key].is_a?(Array) + parent_schema.schema[key].each_with_index do |type,i| + if type.is_a?(Hash) + handle_schema(parent_schema, type) end end end end + # All properties are schemas if parent_schema.schema["properties"] parent_schema.schema["properties"].each do |k,v| - if v['$ref'] - load_ref_schema(parent_schema, v['$ref']) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(v,schema_uri) - if v['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) - end + handle_schema(parent_schema, v) end end - if parent_schema.schema["additionalProperties"].is_a?(Hash) - if parent_schema.schema["additionalProperties"]["$ref"] - load_ref_schema(parent_schema, parent_schema.schema["additionalProperties"]["$ref"]) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(parent_schema.schema["additionalProperties"],schema_uri) - if parent_schema.schema["additionalProperties"]['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) - end - end - + # Items are always schemas if parent_schema.schema["items"] items = parent_schema.schema["items"].clone single = false if !items.is_a?(Array) items = [items] single = true end items.each_with_index do |item,i| - if item['$ref'] - load_ref_schema(parent_schema, item['$ref']) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(item,schema_uri) - if item['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) - end + handle_schema(parent_schema, item) end end - if parent_schema.schema["additionalItems"].is_a?(Hash) - if parent_schema.schema["additionalItems"]['$ref'] - load_ref_schema(parent_schema, parent_schema.schema["additionalItems"]['$ref']) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(parent_schema.schema["additionalItems"],schema_uri) - if parent_schema.schema["additionalItems"]['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) + # Each of these might be schemas + ["additionalProperties", "additionalItems", "dependencies", "extends"].each do |key| + if parent_schema.schema[key].is_a?(Hash) + handle_schema(parent_schema, parent_schema.schema[key]) end end - if parent_schema.schema["dependencies"].is_a?(Hash) - if parent_schema.schema["dependencies"]["$ref"] - load_ref_schema(parent_schema, parent_schema.schema["dependencies"]['$ref']) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(parent_schema.schema["dependencies"],schema_uri) - if parent_schema.schema["dependencies"]['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) - end - end - - if parent_schema.schema["extends"].is_a?(Hash) - if parent_schema.schema["extends"]['$ref'] - load_ref_schema(parent_schema, parent_schema.schema["extends"]['$ref']) - else - schema_uri = parent_schema.uri.clone - schema = JSON::Schema.new(parent_schema.schema["extends"],schema_uri) - if parent_schema.schema["extends"]['id'] - @schemas[schema.uri.to_s] = schema - end - build_schemas(schema) - end - end end + + # Either load a reference schema or create a new schema + def handle_schema(parent_schema, obj) + if obj['$ref'] + load_ref_schema(parent_schema, obj['$ref']) + else + schema_uri = parent_schema.uri.clone + schema = JSON::Schema.new(obj,schema_uri) + if obj['id'] + Validator.add_schema(schema) + end + build_schemas(schema) + end + end class << self def validate(schema, data) validator = JSON::Validator.new(schema, data) @@ -646,9 +587,26 @@ def validate2(schema, data) validator = JSON::Validator.new(schema, data) validator.validate2 end + + def clear_cache + @@schemas = {} if @@cache_schemas == false + end + + def schemas + @@schemas + end + + def add_schema(schema) + @@schemas[schema.uri.to_s] = schema if @@schemas[schema.uri.to_s].nil? + end + + def cache_schemas=(val) + @@cache_schemas = val == true ? true : false + end + end private \ No newline at end of file