lib/jsonschema.rb in jsonschema-2.0.1 vs lib/jsonschema.rb in jsonschema-2.0.2

- old
+ new

@@ -1,10 +1,10 @@ # vim: fileencoding=utf-8 module JSON class Schema - VERSION = '2.0.1' + VERSION = '2.0.2' class ValueError < Exception;end class Undefined;end TypesMap = { "string" => String, "integer" => [Integer, Fixnum], @@ -19,14 +19,23 @@ def initialize interactive @interactive = interactive @refmap = {} end + def keys + @keys ||= [] + end + + def key_path + keys.reject{|k| k == 'self'}.join(" > ") + end + def check_property value, schema, key, parent if schema + keys.push key # if @interactive && schema['readonly'] -# raise ValueError, "#{key} is a readonly field , it can not be changed" +# raise ValueError, "#{key_path} is a readonly field , it can not be changed" # end if schema['id'] @refmap[schema['id']] = schema end @@ -35,11 +44,11 @@ check_property(value, schema['extends'], key, parent) end if value == Undefined unless schema['optional'] - raise ValueError, "#{key}: is missing and it is not optional" + raise ValueError, "#{key_path}: is missing and it is not optional" end # default if @interactive && !parent.include?(key) && !schema['default'].nil? unless schema["readonly"] @@ -59,25 +68,25 @@ begin check_type(value, schema['disallow'], key, parent) rescue ValueError flag = false end - raise ValueError, "#{key}: disallowed value was matched" if flag + raise ValueError, "#{key_path}: disallowed value was matched" if flag end unless value.nil? - if value.instance_of? Array + if value.kind_of? Array if schema['items'] - if schema['items'].instance_of?(Array) + if schema['items'].kind_of?(Array) schema['items'].each_with_index {|val, index| check_property(undefined_check(value, index), schema['items'][index], index, value) } if schema.include?('additionalProperties') additional = schema['additionalProperties'] - if additional.instance_of?(FalseClass) + if additional.kind_of?(FalseClass) if schema['items'].size < value.size - raise ValueError, "#{key}: There are more values in the array than are allowed by the items and additionalProperties restrictions." + raise ValueError, "#{key_path}: There are more values in the array than are allowed by the items and additionalProperties restrictions." end else value.each_with_index {|val, index| check_property(undefined_check(value, index), schema['additionalProperties'], index, value) } @@ -88,121 +97,122 @@ check_property(undefined_check(value, index), schema['items'], index, value) } end end if schema['minItems'] && value.size < schema['minItems'] - raise ValueError, "#{key}: There must be a minimum of #{schema['minItems']} in the array" + raise ValueError, "#{key_path}: There must be a minimum of #{schema['minItems']} in the array" end if schema['maxItems'] && value.size > schema['maxItems'] - raise ValueError, "#{key}: There must be a maximum of #{schema['maxItems']} in the array" + raise ValueError, "#{key_path}: There must be a maximum of #{schema['maxItems']} in the array" end elsif schema['properties'] check_object(value, schema['properties'], schema['additionalProperties']) elsif schema.include?('additionalProperties') additional = schema['additionalProperties'] - unless additional.instance_of?(TrueClass) - if additional.instance_of?(Hash) || additional.instance_of?(FalseClass) + unless additional.kind_of?(TrueClass) + if additional.kind_of?(Hash) || additional.kind_of?(FalseClass) properties = {} value.each {|k, val| - if additional.instance_of?(FalseClass) - raise ValueError, "#{key}: Additional properties not defined by 'properties' are not allowed in field '#{k}'" + if additional.kind_of?(FalseClass) + raise ValueError, "#{key_path}: Additional properties not defined by 'properties' are not allowed in field '#{k}'" else check_property(val, schema['additionalProperties'], k, value) end } else - raise ValueError, "#{key}: additionalProperties schema definition for field '#{}' is not an object" + raise ValueError, "#{key_path}: additionalProperties schema definition for field '#{}' is not an object" end end end - if value.instance_of?(String) + if value.kind_of?(String) # pattern if schema['pattern'] && !(value =~ Regexp.new(schema['pattern'])) - raise ValueError, "#{key}: does not match the regex pattern #{schema['pattern']}" + raise ValueError, "#{key_path}: does not match the regex pattern #{schema['pattern']}" end strlen = value.split(//).size # maxLength if schema['maxLength'] && strlen > schema['maxLength'] - raise ValueError, "#{key}: may only be #{schema['maxLength']} characters long" + raise ValueError, "#{key_path}: may only be #{schema['maxLength']} characters long" end # minLength if schema['minLength'] && strlen < schema['minLength'] - raise ValueError, "#{key}: must be at least #{schema['minLength']} characters long" + raise ValueError, "#{key_path}: must be at least #{schema['minLength']} characters long" end end if value.kind_of?(Numeric) # minimum + minimumCanEqual if schema['minimum'] minimumCanEqual = schema.fetch('minimumCanEqual', Undefined) if minimumCanEqual == Undefined || minimumCanEqual if value < schema['minimum'] - raise ValueError, "#{key}: must have a minimum value of #{schema['minimum']}" + raise ValueError, "#{key_path}: must have a minimum value of #{schema['minimum']}" end else if value <= schema['minimum'] - raise ValueError, "#{key}: must have a minimum value of #{schema['minimum']}" + raise ValueError, "#{key_path}: must have a minimum value of #{schema['minimum']}" end end end # maximum + maximumCanEqual if schema['maximum'] maximumCanEqual = schema.fetch('maximumCanEqual', Undefined) if maximumCanEqual == Undefined || maximumCanEqual if value > schema['maximum'] - raise ValueError, "#{key}: must have a maximum value of #{schema['maximum']}" + raise ValueError, "#{key_path}: must have a maximum value of #{schema['maximum']}" end else if value >= schema['maximum'] - raise ValueError, "#{key}: must have a maximum value of #{schema['maximum']}" + raise ValueError, "#{key_path}: must have a maximum value of #{schema['maximum']}" end end end # maxDecimal if schema['maxDecimal'] && schema['maxDecimal'].kind_of?(Numeric) if value.to_s =~ /\.\d{#{schema['maxDecimal']+1},}/ - raise ValueError, "#{key}: may only have #{schema['maxDecimal']} digits of decimal places" + raise ValueError, "#{key_path}: may only have #{schema['maxDecimal']} digits of decimal places" end end end # enum if schema['enum'] unless(schema['enum'].detect{|enum| enum == value }) - raise ValueError, "#{key}: does not have a value in the enumeration #{schema['enum'].join(", ")}" + raise ValueError, "#{key_path}: does not have a value in the enumeration #{schema['enum'].join(", ")}" end end # description - if schema['description'] && !schema['description'].instance_of?(String) - raise ValueError, "#{key}: The description for field '#{value}' must be a string" + if schema['description'] && !schema['description'].kind_of?(String) + raise ValueError, "#{key_path}: The description for field '#{value}' must be a string" end # title - if schema['title'] && !schema['title'].instance_of?(String) - raise ValueError, "#{key}: The title for field '#{value}' must be a string" + if schema['title'] && !schema['title'].kind_of?(String) + raise ValueError, "#{key_path}: The title for field '#{value}' must be a string" end # format if schema['format'] end end end + keys.pop end end def check_object value, object_type_def, additional - if object_type_def.instance_of? Hash - if !value.instance_of?(Hash) || value.instance_of?(Array) + if object_type_def.kind_of? Hash + if !value.kind_of?(Hash) || value.kind_of?(Array) raise ValueError, "an object is required" end object_type_def.each {|key, odef| if key.index('__') != 0 @@ -210,17 +220,17 @@ end } end value.each {|key, val| if key.index('__') != 0 && object_type_def && !object_type_def[key] && additional == false - raise ValueError, "#{value.class} The property #{key} is not defined in the schema and the schema does not allow additional properties" + raise ValueError, "The property #{key_path} > #{key} is not defined in the schema and the schema does not allow additional properties" end requires = object_type_def && object_type_def[key] && object_type_def[key]['requires'] if requires && !value.include?(requires) - raise ValueError, "the presence of the property #{key} requires that #{requires} also be present" + raise ValueError, "The presence of the property #{key_path} > #{key} requires that #{requires} also be present" end - if object_type_def && object_type_def.instance_of?(Hash) && !object_type_def.include?(key) + if object_type_def && object_type_def.kind_of?(Hash) && !object_type_def.include?(key) check_property(val, additional, key, value) end if !@interactive && val && val['$schema'] check_property(val, val['$schema'], key, value) end @@ -228,11 +238,11 @@ end def check_type value, type, key, parent converted_fieldtype = convert_type(type) if converted_fieldtype - if converted_fieldtype.instance_of? Array + if converted_fieldtype.kind_of? Array datavalid = false converted_fieldtype.each do |t| begin check_type(value, t, key, parent) datavalid = true @@ -240,16 +250,16 @@ rescue ValueError next end end unless datavalid - raise ValueError, "#{key}: #{value.class} value found, but a #{type} is required" + raise ValueError, "#{key_path}: #{value.class} value found, but a #{type} is required" end - elsif converted_fieldtype.instance_of? Hash + elsif converted_fieldtype.kind_of? Hash check_property(value, type, key, parent) else - unless value.instance_of? converted_fieldtype - raise ValueError, "#{key}: #{value.class} value found, but a #{type} is required" + unless value.kind_of? converted_fieldtype + raise ValueError, "#{key_path}: #{value.class} value found, but a #{type} is required" end end end end