json_schema 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,5 @@
1
+ require "json"
2
+
1
3
  module JsonSchema
2
4
  class Schema
3
5
  @@copyable = []
@@ -13,33 +15,116 @@ module JsonSchema
13
15
  class_eval("def #{attr} ; !@#{attr}.nil? ? @#{attr} : #{default} ; end")
14
16
  end
15
17
 
18
+ def initialize
19
+ @clones = Set.new
20
+ end
21
+
16
22
  # Rather than a normal schema, the node may be a JSON Reference. In this
17
23
  # case, no other attributes will be filled in except for #parent.
18
- attr_copyable :reference
24
+ attr_accessor :reference
25
+
26
+ attr_copyable :expanded
19
27
 
20
- # the schema keeps a reference to the data it was initialized from for JSON
21
- # Pointer resolution
28
+ # A reference to the data which the Schema was initialized from. Used for
29
+ # resolving JSON Pointer references.
30
+ #
31
+ # Type: Hash
22
32
  attr_copyable :data
23
33
 
24
- # parent and children schemas
34
+ #
35
+ # Relations
36
+ #
37
+
38
+ # Parent Schema object. Child may come from any of `definitions`,
39
+ # `properties`, `anyOf`, etc.
40
+ #
41
+ # Type: Schema
25
42
  attr_copyable :parent
26
43
 
27
- # the normalize URI of this schema
44
+ # Collection of clones of this schema object, meaning all Schemas that were
45
+ # initialized after the original. Used for JSON Reference expansion. The
46
+ # only copy not present in this set is the original Schema object.
47
+ #
48
+ # Type: Set[Schema]
49
+ attr_copyable :clones
50
+
51
+ # The normalized URI of this schema. Note that child schemas inherit a URI
52
+ # from their parent unless they have one explicitly defined, so this is
53
+ # likely not a unique value in any given schema hierarchy.
54
+ #
55
+ # Type: String
28
56
  attr_copyable :uri
29
57
 
30
- # basic descriptors
58
+ #
59
+ # Metadata
60
+ #
61
+
62
+ # Alters resolution scope. This value is used along with the parent scope's
63
+ # URI to build a new address for this schema. Relative ID's will append to
64
+ # the parent, and absolute URI's will replace it.
65
+ #
66
+ # Type: String
31
67
  attr_copyable :id
68
+
69
+ # Short title of the schema.
70
+ #
71
+ # Type: String
32
72
  attr_copyable :title
73
+
74
+ # More detailed description of the schema.
75
+ #
76
+ # Type: String
33
77
  attr_copyable :description
78
+
79
+ # Default JSON value for this particular schema
80
+ #
81
+ # Type: [any]
34
82
  attr_copyable :default
35
83
 
36
- # validation: any
84
+ #
85
+ # Validation: Any
86
+ #
87
+
88
+ # A collection of subschemas of which data must validate against the full
89
+ # set of to be valid.
90
+ #
91
+ # Type: Array[Schema]
37
92
  attr_copyable :all_of
93
+
94
+ # A collection of subschemas of which data must validate against any schema
95
+ # in the set to be be valid.
96
+ #
97
+ # Type: Array[Schema]
38
98
  attr_copyable :any_of
99
+
100
+ # A collection of inlined subschemas. Standard convention is to subschemas
101
+ # here and reference them from elsewhere.
102
+ #
103
+ # Type: Hash[String => Schema]
39
104
  attr_copyable :definitions
105
+
106
+ # A collection of objects that must include the data for it to be valid.
107
+ #
108
+ # Type: Array
40
109
  attr_copyable :enum
110
+
111
+ # A collection of subschemas of which data must validate against exactly
112
+ # one of to be valid.
113
+ #
114
+ # Type: Array[Schema]
41
115
  attr_copyable :one_of
116
+
117
+
118
+ # A subschema which data must not validate against to be valid.
119
+ #
120
+ # Type: Schema
42
121
  attr_copyable :not
122
+
123
+ # An array of types that data is allowed to be. The spec allows this to be
124
+ # a string as well, but the parser will always normalize this to an array
125
+ # of strings.
126
+ #
127
+ # Type: Array[String]
43
128
  attr_copyable :type
44
129
 
45
130
  # validation: array
@@ -97,7 +182,7 @@ module JsonSchema
97
182
 
98
183
  # allow booleans to be access with question mark
99
184
  alias :additional_items? :additional_items
100
- alias :additional_properties? :additional_properties
185
+ alias :expanded? :expanded
101
186
  alias :max_exclusive? :max_exclusive
102
187
  alias :min_exclusive? :min_exclusive
103
188
  alias :read_only? :read_only
@@ -123,6 +208,53 @@ module JsonSchema
123
208
  true
124
209
  end
125
210
 
211
+ def inspect
212
+ str = inspect_schema
213
+ str = JSON.pretty_generate(str).gsub(/\\?"/, '') if str.is_a?(Hash)
214
+ "\#<JsonSchema::Schema #{str}>"
215
+ end
216
+
217
+ def inspect_schema
218
+ if reference
219
+ str = reference.to_s
220
+ str += " [EXPANDED]" if expanded?
221
+ str += " [CLONE]" if !original?
222
+ str
223
+ else
224
+ hash = {}
225
+ @@copyable.each do |copyable|
226
+ next if [:@clones, :@data, :@parent, :@uri].include?(copyable)
227
+ if value = instance_variable_get(copyable)
228
+ if value.is_a?(Array)
229
+ if !value.empty?
230
+ hash[copyable] = value.map { |v| inspect_value(v) }
231
+ end
232
+ elsif value.is_a?(Hash)
233
+ if !value.empty?
234
+ hash[copyable] =
235
+ Hash[*value.map { |k, v| [k, inspect_value(v)] }.flatten]
236
+ end
237
+ else
238
+ hash[copyable] = inspect_value(value)
239
+ end
240
+ end
241
+ end
242
+ hash
243
+ end
244
+ end
245
+
246
+ def inspect_value(value)
247
+ if value.is_a?(Schema)
248
+ value.inspect_schema
249
+ else
250
+ value.inspect
251
+ end
252
+ end
253
+
254
+ def original?
255
+ !clones.include?(self)
256
+ end
257
+
126
258
  def validate(data)
127
259
  validator = Validator.new(self)
128
260
  valid = validator.validate(data)
@@ -86,13 +86,25 @@ module JsonSchema
86
86
  end
87
87
 
88
88
  def validate_additional_properties(schema, data, errors)
89
- return true if schema.additional_properties?
90
- if (extra = data.keys - schema.properties.keys).empty?
91
- true
89
+ return true if schema.additional_properties == true
90
+
91
+ extra = data.keys - schema.properties.keys
92
+
93
+ # schema indicates that all properties not in `properties` should be
94
+ # validated according to subschema
95
+ if schema.additional_properties.is_a?(Schema)
96
+ extra.each do |key|
97
+ validate_data(schema.additional_properties, data[key], errors)
98
+ end
99
+ # boolean indicates whether additional properties are allowed
92
100
  else
93
- message = %{Extra keys in object: #{extra.sort.join(", ")}.}
94
- errors << SchemaError.new(schema, message)
95
- false
101
+ if extra.empty?
102
+ true
103
+ else
104
+ message = %{Extra keys in object: #{extra.sort.join(", ")}.}
105
+ errors << SchemaError.new(schema, message)
106
+ false
107
+ end
96
108
  end
97
109
  end
98
110
 
@@ -143,8 +155,10 @@ module JsonSchema
143
155
  data =~ IPV4_PATTERN
144
156
  when "ipv6"
145
157
  data =~ IPV6_PATTERN
158
+ when "regex"
159
+ Regexp.new(data) rescue false
146
160
  when "uri"
147
- data =~ URI.regexp
161
+ URI.parse(data) rescue false
148
162
  when "uuid"
149
163
  data =~ UUID_PATTERN
150
164
  end
@@ -347,6 +361,7 @@ module JsonSchema
347
361
  return true if schema.properties.empty?
348
362
  valid = true
349
363
  schema.properties.each do |key, subschema|
364
+
350
365
  if value = data[key]
351
366
  valid = strict_and valid, validate_data(subschema, value, errors)
352
367
  end
@@ -0,0 +1,168 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-04/hyper-schema#",
3
+ "id": "http://json-schema.org/draft-04/hyper-schema#",
4
+ "title": "JSON Hyper-Schema",
5
+ "allOf": [
6
+ {
7
+ "$ref": "http://json-schema.org/draft-04/schema#"
8
+ }
9
+ ],
10
+ "properties": {
11
+ "additionalItems": {
12
+ "anyOf": [
13
+ {
14
+ "type": "boolean"
15
+ },
16
+ {
17
+ "$ref": "#"
18
+ }
19
+ ]
20
+ },
21
+ "additionalProperties": {
22
+ "anyOf": [
23
+ {
24
+ "type": "boolean"
25
+ },
26
+ {
27
+ "$ref": "#"
28
+ }
29
+ ]
30
+ },
31
+ "dependencies": {
32
+ "additionalProperties": {
33
+ "anyOf": [
34
+ {
35
+ "$ref": "#"
36
+ },
37
+ {
38
+ "type": "array"
39
+ }
40
+ ]
41
+ }
42
+ },
43
+ "items": {
44
+ "anyOf": [
45
+ {
46
+ "$ref": "#"
47
+ },
48
+ {
49
+ "$ref": "#/definitions/schemaArray"
50
+ }
51
+ ]
52
+ },
53
+ "definitions": {
54
+ "additionalProperties": {
55
+ "$ref": "#"
56
+ }
57
+ },
58
+ "patternProperties": {
59
+ "additionalProperties": {
60
+ "$ref": "#"
61
+ }
62
+ },
63
+ "properties": {
64
+ "additionalProperties": {
65
+ "$ref": "#"
66
+ }
67
+ },
68
+ "allOf": {
69
+ "$ref": "#/definitions/schemaArray"
70
+ },
71
+ "anyOf": {
72
+ "$ref": "#/definitions/schemaArray"
73
+ },
74
+ "oneOf": {
75
+ "$ref": "#/definitions/schemaArray"
76
+ },
77
+ "not": {
78
+ "$ref": "#"
79
+ },
80
+
81
+ "links": {
82
+ "type": "array",
83
+ "items": {
84
+ "$ref": "#/definitions/linkDescription"
85
+ }
86
+ },
87
+ "fragmentResolution": {
88
+ "type": "string"
89
+ },
90
+ "media": {
91
+ "type": "object",
92
+ "properties": {
93
+ "type": {
94
+ "description": "A media type, as described in RFC 2046",
95
+ "type": "string"
96
+ },
97
+ "binaryEncoding": {
98
+ "description": "A content encoding scheme, as described in RFC 2045",
99
+ "type": "string"
100
+ }
101
+ }
102
+ },
103
+ "pathStart": {
104
+ "description": "Instances' URIs must start with this value for this schema to apply to them",
105
+ "type": "string",
106
+ "format": "uri"
107
+ }
108
+ },
109
+ "definitions": {
110
+ "schemaArray": {
111
+ "type": "array",
112
+ "items": {
113
+ "$ref": "#"
114
+ }
115
+ },
116
+ "linkDescription": {
117
+ "title": "Link Description Object",
118
+ "type": "object",
119
+ "required": [ "href", "rel" ],
120
+ "properties": {
121
+ "href": {
122
+ "description": "a URI template, as defined by RFC 6570, with the addition of the $, ( and ) characters for pre-processing",
123
+ "type": "string"
124
+ },
125
+ "rel": {
126
+ "description": "relation to the target resource of the link",
127
+ "type": "string"
128
+ },
129
+ "title": {
130
+ "description": "a title for the link",
131
+ "type": "string"
132
+ },
133
+ "targetSchema": {
134
+ "description": "JSON Schema describing the link target",
135
+ "$ref": "#"
136
+ },
137
+ "mediaType": {
138
+ "description": "media type (as defined by RFC 2046) describing the link target",
139
+ "type": "string"
140
+ },
141
+ "method": {
142
+ "description": "method for requesting the target of the link (e.g. for HTTP this might be \"GET\" or \"DELETE\")",
143
+ "type": "string"
144
+ },
145
+ "encType": {
146
+ "description": "The media type in which to submit data along with the request",
147
+ "type": "string",
148
+ "default": "application/json"
149
+ },
150
+ "schema": {
151
+ "description": "Schema describing the data to submit along with the request",
152
+ "$ref": "#"
153
+ }
154
+ }
155
+ }
156
+ },
157
+ "links": [
158
+ {
159
+ "rel": "self",
160
+ "href": "{+id}"
161
+ },
162
+ {
163
+ "rel": "full",
164
+ "href": "{+($ref)}"
165
+ }
166
+ ]
167
+ }
168
+
@@ -0,0 +1,150 @@
1
+ {
2
+ "id": "http://json-schema.org/draft-04/schema#",
3
+ "$schema": "http://json-schema.org/draft-04/schema#",
4
+ "description": "Core schema meta-schema",
5
+ "definitions": {
6
+ "schemaArray": {
7
+ "type": "array",
8
+ "minItems": 1,
9
+ "items": { "$ref": "#" }
10
+ },
11
+ "positiveInteger": {
12
+ "type": "integer",
13
+ "minimum": 0
14
+ },
15
+ "positiveIntegerDefault0": {
16
+ "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
17
+ },
18
+ "simpleTypes": {
19
+ "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
20
+ },
21
+ "stringArray": {
22
+ "type": "array",
23
+ "items": { "type": "string" },
24
+ "minItems": 1,
25
+ "uniqueItems": true
26
+ }
27
+ },
28
+ "type": "object",
29
+ "properties": {
30
+ "id": {
31
+ "type": "string",
32
+ "format": "uri"
33
+ },
34
+ "$schema": {
35
+ "type": "string",
36
+ "format": "uri"
37
+ },
38
+ "title": {
39
+ "type": "string"
40
+ },
41
+ "description": {
42
+ "type": "string"
43
+ },
44
+ "default": {},
45
+ "multipleOf": {
46
+ "type": "number",
47
+ "minimum": 0,
48
+ "exclusiveMinimum": true
49
+ },
50
+ "maximum": {
51
+ "type": "number"
52
+ },
53
+ "exclusiveMaximum": {
54
+ "type": "boolean",
55
+ "default": false
56
+ },
57
+ "minimum": {
58
+ "type": "number"
59
+ },
60
+ "exclusiveMinimum": {
61
+ "type": "boolean",
62
+ "default": false
63
+ },
64
+ "maxLength": { "$ref": "#/definitions/positiveInteger" },
65
+ "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
66
+ "pattern": {
67
+ "type": "string",
68
+ "format": "regex"
69
+ },
70
+ "additionalItems": {
71
+ "anyOf": [
72
+ { "type": "boolean" },
73
+ { "$ref": "#" }
74
+ ],
75
+ "default": {}
76
+ },
77
+ "items": {
78
+ "anyOf": [
79
+ { "$ref": "#" },
80
+ { "$ref": "#/definitions/schemaArray" }
81
+ ],
82
+ "default": {}
83
+ },
84
+ "maxItems": { "$ref": "#/definitions/positiveInteger" },
85
+ "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
86
+ "uniqueItems": {
87
+ "type": "boolean",
88
+ "default": false
89
+ },
90
+ "maxProperties": { "$ref": "#/definitions/positiveInteger" },
91
+ "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
92
+ "required": { "$ref": "#/definitions/stringArray" },
93
+ "additionalProperties": {
94
+ "anyOf": [
95
+ { "type": "boolean" },
96
+ { "$ref": "#" }
97
+ ],
98
+ "default": {}
99
+ },
100
+ "definitions": {
101
+ "type": "object",
102
+ "additionalProperties": { "$ref": "#" },
103
+ "default": {}
104
+ },
105
+ "properties": {
106
+ "type": "object",
107
+ "additionalProperties": { "$ref": "#" },
108
+ "default": {}
109
+ },
110
+ "patternProperties": {
111
+ "type": "object",
112
+ "additionalProperties": { "$ref": "#" },
113
+ "default": {}
114
+ },
115
+ "dependencies": {
116
+ "type": "object",
117
+ "additionalProperties": {
118
+ "anyOf": [
119
+ { "$ref": "#" },
120
+ { "$ref": "#/definitions/stringArray" }
121
+ ]
122
+ }
123
+ },
124
+ "enum": {
125
+ "type": "array",
126
+ "minItems": 1,
127
+ "uniqueItems": true
128
+ },
129
+ "type": {
130
+ "anyOf": [
131
+ { "$ref": "#/definitions/simpleTypes" },
132
+ {
133
+ "type": "array",
134
+ "items": { "$ref": "#/definitions/simpleTypes" },
135
+ "minItems": 1,
136
+ "uniqueItems": true
137
+ }
138
+ ]
139
+ },
140
+ "allOf": { "$ref": "#/definitions/schemaArray" },
141
+ "anyOf": { "$ref": "#/definitions/schemaArray" },
142
+ "oneOf": { "$ref": "#/definitions/schemaArray" },
143
+ "not": { "$ref": "#" }
144
+ },
145
+ "dependencies": {
146
+ "exclusiveMaximum": [ "maximum" ],
147
+ "exclusiveMinimum": [ "minimum" ]
148
+ },
149
+ "default": {}
150
+ }