jschematic 0.0.6 → 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.
- data/Gemfile.lock +1 -1
- data/History.txt +7 -0
- data/README.md +27 -12
- data/features/disallow.feature +33 -0
- data/features/divisible_by.feature +17 -0
- data/features/extends.feature +115 -0
- data/features/format.feature +3 -2
- data/features/ref.feature +0 -1
- data/features/type.feature +2 -2
- data/jschematic.gemspec +1 -1
- data/lib/jschematic.rb +5 -0
- data/lib/jschematic/attributes.rb +3 -0
- data/lib/jschematic/attributes/disallow.rb +16 -0
- data/lib/jschematic/attributes/divisible_by.rb +20 -0
- data/lib/jschematic/attributes/extends.rb +30 -0
- data/lib/jschematic/attributes/format.rb +1 -0
- data/lib/jschematic/attributes/maximum.rb +2 -3
- data/lib/jschematic/attributes/minimum.rb +1 -2
- data/lib/jschematic/attributes/type.rb +6 -6
- data/lib/jschematic/schema.rb +6 -7
- data/spec/jschematic/attributes/disallow_spec.rb +15 -0
- data/spec/jschematic/attributes/divisible_by_spec.rb +12 -0
- data/spec/jschematic/schema_spec.rb +16 -0
- metadata +17 -4
data/Gemfile.lock
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== In Git
|
2
|
+
* Store $schema values on Schema objects if available (Mike Sassak)
|
3
|
+
* Support divisibleBy (Mike Sassak)
|
4
|
+
* Store unknown schema attributes on the schema, and warn when Jschematic.debug
|
5
|
+
is set to true (Mike Sassak)
|
6
|
+
* Support disallow (Mike Sassak)
|
7
|
+
|
1
8
|
== 0.0.6
|
2
9
|
* Improve and document the Context API (Mike Sassak)
|
3
10
|
|
data/README.md
CHANGED
@@ -1,21 +1,29 @@
|
|
1
1
|
# Jschematic
|
2
2
|
|
3
|
-
Jschematic is a JSON Schema
|
3
|
+
Jschematic is a JSON Schema Validator for Ruby. Its aim is to validate
|
4
|
+
schemas conforming to the most recent version of the JSON Schema draft
|
5
|
+
standard, which today means v3.
|
4
6
|
|
5
|
-
|
6
|
-
it is a
|
7
|
+
Supporting older versions of the standard is not out of the question,
|
8
|
+
but it is not a primary development focus.
|
7
9
|
|
8
|
-
|
10
|
+
## Status
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
* divisibleBy
|
13
|
-
* disallow
|
12
|
+
Core schema: fully supported
|
13
|
+
Hyper schema: not supported
|
14
14
|
|
15
|
-
|
16
|
-
implemented.
|
15
|
+
The format attribute supports only these formats:
|
17
16
|
|
18
|
-
|
17
|
+
* date-time
|
18
|
+
* date
|
19
|
+
* ip-address
|
20
|
+
* ipv6
|
21
|
+
* uri
|
22
|
+
|
23
|
+
Adding ad-hoc support for different formats should be relatively painless.
|
24
|
+
Look in jschematic/attributes/format.rb to get started.
|
25
|
+
|
26
|
+
Please report any bugs you find in the issue tracker here:
|
19
27
|
https://github.com/msassak/jschematic/issues.
|
20
28
|
|
21
29
|
## Basic Usage
|
@@ -35,9 +43,16 @@ Pass extra schemas to inform the validation context:
|
|
35
43
|
|
36
44
|
Jschematic.validate(json, schema, :context => [cs1, cs2])
|
37
45
|
|
38
|
-
Each context schema will be
|
46
|
+
Each context schema will be consulted in those cases where cross-schema
|
39
47
|
referencing is allowed, e.g. $ref.
|
40
48
|
|
49
|
+
To enable debugging support, set :debug to true in the options hash:
|
50
|
+
|
51
|
+
Jschematic.validate!(json, schema, :debug => true)
|
52
|
+
|
53
|
+
With debugging on a warning is printed when schema contain unknown
|
54
|
+
attributes.
|
55
|
+
|
41
56
|
## Testing
|
42
57
|
|
43
58
|
$ cucumber
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Feature: Core schema: disallow
|
2
|
+
|
3
|
+
Scenario: simple type
|
4
|
+
When the schema is:
|
5
|
+
"""
|
6
|
+
{
|
7
|
+
"disallow": "integer"
|
8
|
+
}
|
9
|
+
"""
|
10
|
+
Then these are valid JSON:
|
11
|
+
| "oh hai" |
|
12
|
+
| 3.14159 |
|
13
|
+
| [1,2,3] |
|
14
|
+
But '42' is not valid JSON
|
15
|
+
|
16
|
+
Scenario: complex type
|
17
|
+
When the schema is:
|
18
|
+
"""
|
19
|
+
{
|
20
|
+
"disallow": [
|
21
|
+
"string",
|
22
|
+
{ "type": "float" }
|
23
|
+
]
|
24
|
+
}
|
25
|
+
"""
|
26
|
+
Then these are valid JSON:
|
27
|
+
| 42 |
|
28
|
+
| [1,2,3,4] |
|
29
|
+
| { "foo": "bar" } |
|
30
|
+
But these are not valid JSON:
|
31
|
+
| "hi how are you?" |
|
32
|
+
| 3.14159 |
|
33
|
+
|
@@ -0,0 +1,115 @@
|
|
1
|
+
Feature: Core schema: extends
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given the validation context contains this schema:
|
5
|
+
"""
|
6
|
+
{
|
7
|
+
"id": "person",
|
8
|
+
"properties": {
|
9
|
+
"name": {
|
10
|
+
"type": "string",
|
11
|
+
"required": true
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
"""
|
16
|
+
|
17
|
+
Scenario: extending a single schema by ID
|
18
|
+
When the schema is:
|
19
|
+
"""
|
20
|
+
{
|
21
|
+
"properties": {
|
22
|
+
"age": {
|
23
|
+
"type": "integer",
|
24
|
+
"required": true
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"extends": "person"
|
28
|
+
}
|
29
|
+
"""
|
30
|
+
Then this is valid JSON:
|
31
|
+
"""
|
32
|
+
{
|
33
|
+
"name": "Felizberto Albi Perez Fernandez Mariposa Carlos Velasquez",
|
34
|
+
"age": 24
|
35
|
+
}
|
36
|
+
"""
|
37
|
+
But this is not valid JSON:
|
38
|
+
"""
|
39
|
+
{
|
40
|
+
"age": 24
|
41
|
+
}
|
42
|
+
"""
|
43
|
+
|
44
|
+
Scenario: extending a literal schema
|
45
|
+
When the schema is:
|
46
|
+
"""
|
47
|
+
{
|
48
|
+
"properties": {
|
49
|
+
"age": {
|
50
|
+
"type": "integer",
|
51
|
+
"required": true
|
52
|
+
}
|
53
|
+
},
|
54
|
+
|
55
|
+
"extends": {
|
56
|
+
"properties": {
|
57
|
+
"name": {
|
58
|
+
"type": "string",
|
59
|
+
"required": true
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
"""
|
65
|
+
Then this is valid JSON:
|
66
|
+
"""
|
67
|
+
{
|
68
|
+
"name": "Felizberto Albi Perez Fernandez Mariposa Carlos Velasquez",
|
69
|
+
"age": 24
|
70
|
+
}
|
71
|
+
"""
|
72
|
+
But this is not valid JSON:
|
73
|
+
"""
|
74
|
+
{
|
75
|
+
"age": 24
|
76
|
+
}
|
77
|
+
"""
|
78
|
+
|
79
|
+
Scenario: extending multiple schemas
|
80
|
+
When the schema is:
|
81
|
+
"""
|
82
|
+
{
|
83
|
+
"properties": {
|
84
|
+
"age": {
|
85
|
+
"type": "integer",
|
86
|
+
"required": true
|
87
|
+
}
|
88
|
+
},
|
89
|
+
"extends": [
|
90
|
+
"person",
|
91
|
+
|
92
|
+
{
|
93
|
+
"properties": {
|
94
|
+
"height": {
|
95
|
+
"type": "number",
|
96
|
+
"required": true
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
]
|
101
|
+
}
|
102
|
+
"""
|
103
|
+
Then this is valid JSON:
|
104
|
+
"""
|
105
|
+
{
|
106
|
+
"name": "Felizberto Albi Perez Fernandez Mariposa Carlos Velasquez",
|
107
|
+
"age": 24,
|
108
|
+
"height": 5.8
|
109
|
+
}
|
110
|
+
"""
|
111
|
+
But these are not valid JSON:
|
112
|
+
| { "age": 24, "height": 6 } |
|
113
|
+
| { "name": "Foo bar" } |
|
114
|
+
|
115
|
+
|
data/features/format.feature
CHANGED
data/features/ref.feature
CHANGED
data/features/type.feature
CHANGED
@@ -61,12 +61,12 @@ Feature: Core Schema: type
|
|
61
61
|
When the schema is '{ "type": ["string", "null"] }'
|
62
62
|
Then 'null' is valid JSON
|
63
63
|
|
64
|
-
Scenario: union with schema element
|
64
|
+
Scenario: union with schema element
|
65
65
|
When the schema is:
|
66
66
|
"""
|
67
67
|
{
|
68
68
|
"type": [
|
69
|
-
"string",
|
69
|
+
"string",
|
70
70
|
{ "type": "integer", "maximum": 2112 }
|
71
71
|
]
|
72
72
|
}
|
data/jschematic.gemspec
CHANGED
data/lib/jschematic.rb
CHANGED
@@ -18,6 +18,9 @@ require 'jschematic/attributes/min_length'
|
|
18
18
|
require 'jschematic/attributes/max_length'
|
19
19
|
require 'jschematic/attributes/enum'
|
20
20
|
require 'jschematic/attributes/format'
|
21
|
+
require 'jschematic/attributes/divisible_by'
|
22
|
+
require 'jschematic/attributes/disallow'
|
23
|
+
require 'jschematic/attributes/extends'
|
21
24
|
require 'jschematic/attributes/ref'
|
22
25
|
|
23
26
|
module Jschematic
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Jschematic
|
2
|
+
module Attributes
|
3
|
+
class Disallow < Type
|
4
|
+
# disallow inverts the type attribute, so it succeeds if type fails
|
5
|
+
def accepts?(instance)
|
6
|
+
inverted = begin
|
7
|
+
super
|
8
|
+
false
|
9
|
+
rescue ValidationError
|
10
|
+
true
|
11
|
+
end
|
12
|
+
inverted || fail_validation!("instance not to be of type '#{type}'", instance)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'jschematic/element'
|
2
|
+
|
3
|
+
module Jschematic
|
4
|
+
module Attributes
|
5
|
+
class DivisibleBy
|
6
|
+
include Jschematic::Element
|
7
|
+
|
8
|
+
def initialize(divisor)
|
9
|
+
@divisor = divisor
|
10
|
+
end
|
11
|
+
|
12
|
+
def accepts?(dividend)
|
13
|
+
return true unless Numeric === dividend
|
14
|
+
|
15
|
+
remainder = (dividend % @divisor)
|
16
|
+
(remainder == 0) || fail_validation!("#{dividend} modulo #{@divisor} to have a remainder of 0", remainder)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
3
|
+
require 'jschematic/element'
|
4
|
+
|
5
|
+
module Jschematic
|
6
|
+
module Attributes
|
7
|
+
class Extends
|
8
|
+
include Jschematic::Element
|
9
|
+
|
10
|
+
def initialize(id_or_schema_or_array_of_schemas)
|
11
|
+
@schema = id_or_schema_or_array_of_schemas
|
12
|
+
end
|
13
|
+
|
14
|
+
def accepts?(instance)
|
15
|
+
case @schema
|
16
|
+
when String
|
17
|
+
uri = Addressable::URI.parse(@schema)
|
18
|
+
schema = Schema.schema_for(uri)
|
19
|
+
schema.accepts?(instance)
|
20
|
+
when Hash
|
21
|
+
Schema.new(@schema).accepts?(instance)
|
22
|
+
when Array
|
23
|
+
@schema.all? do |schema|
|
24
|
+
Extends.new(schema).accepts?(instance)
|
25
|
+
end
|
26
|
+
end || fail_validation!(@schema, instance)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -10,10 +10,9 @@ module Jschematic
|
|
10
10
|
def initialize(maximum)
|
11
11
|
@maximum = maximum
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def accepts?(number)
|
15
|
-
return true unless
|
16
|
-
return true unless (number.kind_of?(Integer) || number.kind_of?(Float))
|
15
|
+
return true unless Numeric === number
|
17
16
|
|
18
17
|
(number <= maximum) || fail_validation!("<= #{@maximum}", number)
|
19
18
|
end
|
@@ -12,8 +12,7 @@ module Jschematic
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def accepts?(number)
|
15
|
-
return true unless
|
16
|
-
return true unless (number.kind_of?(Integer) || number.kind_of?(Float))
|
15
|
+
return true unless Numeric === number
|
17
16
|
|
18
17
|
(number >= minimum) || fail_validation!(">= #{@minimum}", number)
|
19
18
|
end
|
@@ -18,7 +18,7 @@ module Jschematic
|
|
18
18
|
when /^object$/
|
19
19
|
assert_kind_of([Hash], instance)
|
20
20
|
when /^number$/
|
21
|
-
assert_kind_of([
|
21
|
+
assert_kind_of([Numeric], instance)
|
22
22
|
when /^integer$/
|
23
23
|
assert_kind_of([Integer], instance)
|
24
24
|
when /^boolean$/
|
@@ -28,7 +28,7 @@ module Jschematic
|
|
28
28
|
when /^any$/
|
29
29
|
true
|
30
30
|
when Array # union
|
31
|
-
# TODO: this is gross. A specific Union type is likely called for
|
31
|
+
# TODO: this is gross. A specific Union type is likely called for
|
32
32
|
type.any? do |union_type|
|
33
33
|
begin
|
34
34
|
if String===union_type
|
@@ -39,16 +39,16 @@ module Jschematic
|
|
39
39
|
rescue ValidationError
|
40
40
|
false
|
41
41
|
end
|
42
|
-
end
|
43
|
-
else
|
44
|
-
# TODO: probably worth just putting in explicit mapping for all
|
42
|
+
end || fail_validation!(type, instance)
|
43
|
+
else
|
44
|
+
# TODO: probably worth just putting in explicit mapping for all
|
45
45
|
# JSON schema types--there are only a few left
|
46
46
|
assert_kind_of([constantize(type)], instance)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
51
|
-
|
51
|
+
|
52
52
|
def assert_kind_of(klassen, instance)
|
53
53
|
klassen.any?{ |klass| instance.kind_of?(klass) } || fail_validation!(klassen, instance)
|
54
54
|
end
|
data/lib/jschematic/schema.rb
CHANGED
@@ -34,7 +34,7 @@ module Jschematic
|
|
34
34
|
@schemas ||= {}
|
35
35
|
end
|
36
36
|
|
37
|
-
attr_reader :default, :title, :description
|
37
|
+
attr_reader :default, :title, :description, :schema, :unknown_attributes
|
38
38
|
|
39
39
|
attr_accessor :name
|
40
40
|
attr_writer :parent
|
@@ -45,8 +45,11 @@ module Jschematic
|
|
45
45
|
@default = @raw_schema.delete("default")
|
46
46
|
@title = @raw_schema.delete("title") || ""
|
47
47
|
@description = @raw_schema.delete("description") || ""
|
48
|
+
@schema = @raw_schema.delete("$schema")
|
48
49
|
@id = Addressable::URI.parse(@raw_schema.delete("id") || "")
|
49
50
|
|
51
|
+
@unknown_attributes = {}
|
52
|
+
|
50
53
|
self.class.add_schema(@id, self) unless @id.to_s.empty?
|
51
54
|
|
52
55
|
@raw_schema.each_pair do |attribute, value|
|
@@ -54,12 +57,8 @@ module Jschematic
|
|
54
57
|
attribute = Attributes[attribute].new(value){ |dep| @raw_schema[dep] }
|
55
58
|
add_child(attribute)
|
56
59
|
rescue NameError => e
|
57
|
-
|
58
|
-
|
59
|
-
# report information.
|
60
|
-
# should we create accessors for property on the schema?
|
61
|
-
# we could have Attributes.[] raise a special exception rather than NameError
|
62
|
-
puts "NameError #{e} encountered... continuing"
|
60
|
+
warn "Attribute lookup failed for '#{attribute}' with: #{e.message}" if Jschematic.debug
|
61
|
+
@unknown_attributes[attribute] = value
|
63
62
|
end
|
64
63
|
end
|
65
64
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Jschematic
|
4
|
+
module Attributes
|
5
|
+
describe Disallow do
|
6
|
+
subject { Disallow.new("any") }
|
7
|
+
it { should_not accept("a string") }
|
8
|
+
it { should_not accept(1234) }
|
9
|
+
it { should_not accept(1.234) }
|
10
|
+
it { should_not accept([1,2,3]) }
|
11
|
+
it { should_not accept({"foo" => "bar"}) }
|
12
|
+
it { should_not accept(true) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -41,5 +41,21 @@ module Jschematic
|
|
41
41
|
schema.id.should == "http://www.example.com/parent/child"
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe "#schema" do
|
46
|
+
it "contains the value of the $schema property if it exists" do
|
47
|
+
schema = Schema.new({ "$schema" => "http://json-schema.org/draft-03/schema#" }).schema
|
48
|
+
schema.should == "http://json-schema.org/draft-03/schema#"
|
49
|
+
|
50
|
+
Schema.new({}).schema.should be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#unknown_attributes" do
|
55
|
+
it "contains all the unknown attributes from the input schema" do
|
56
|
+
schema = Schema.new({ "flarble" => [:oh, :my, :blargle], "type" => "string" })
|
57
|
+
schema.unknown_attributes.should == { "flarble" => [:oh, :my, :blargle] }
|
58
|
+
end
|
59
|
+
end
|
44
60
|
end
|
45
61
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 9
|
9
|
+
version: 0.0.9
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Mike Sassak
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-05-04 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -90,7 +90,10 @@ files:
|
|
90
90
|
- cucumber.yml
|
91
91
|
- features/default.feature
|
92
92
|
- features/dependencies.feature
|
93
|
+
- features/disallow.feature
|
94
|
+
- features/divisible_by.feature
|
93
95
|
- features/enum.feature
|
96
|
+
- features/extends.feature
|
94
97
|
- features/format.feature
|
95
98
|
- features/id.feature
|
96
99
|
- features/items.feature
|
@@ -110,9 +113,12 @@ files:
|
|
110
113
|
- lib/jschematic/attributes/additional_items.rb
|
111
114
|
- lib/jschematic/attributes/additional_properties.rb
|
112
115
|
- lib/jschematic/attributes/dependencies.rb
|
116
|
+
- lib/jschematic/attributes/disallow.rb
|
117
|
+
- lib/jschematic/attributes/divisible_by.rb
|
113
118
|
- lib/jschematic/attributes/enum.rb
|
114
119
|
- lib/jschematic/attributes/exclusive_maximum.rb
|
115
120
|
- lib/jschematic/attributes/exclusive_minimum.rb
|
121
|
+
- lib/jschematic/attributes/extends.rb
|
116
122
|
- lib/jschematic/attributes/format.rb
|
117
123
|
- lib/jschematic/attributes/items.rb
|
118
124
|
- lib/jschematic/attributes/max_items.rb
|
@@ -134,6 +140,8 @@ files:
|
|
134
140
|
- lib/jschematic/errors.rb
|
135
141
|
- lib/jschematic/exceptions.rb
|
136
142
|
- lib/jschematic/schema.rb
|
143
|
+
- spec/jschematic/attributes/disallow_spec.rb
|
144
|
+
- spec/jschematic/attributes/divisible_by_spec.rb
|
137
145
|
- spec/jschematic/attributes/enum_spec.rb
|
138
146
|
- spec/jschematic/attributes/format_spec.rb
|
139
147
|
- spec/jschematic/attributes/max_items_spec.rb
|
@@ -177,11 +185,14 @@ rubyforge_project:
|
|
177
185
|
rubygems_version: 1.3.7
|
178
186
|
signing_key:
|
179
187
|
specification_version: 3
|
180
|
-
summary: jschematic 0.0.
|
188
|
+
summary: jschematic 0.0.9
|
181
189
|
test_files:
|
182
190
|
- features/default.feature
|
183
191
|
- features/dependencies.feature
|
192
|
+
- features/disallow.feature
|
193
|
+
- features/divisible_by.feature
|
184
194
|
- features/enum.feature
|
195
|
+
- features/extends.feature
|
185
196
|
- features/format.feature
|
186
197
|
- features/id.feature
|
187
198
|
- features/items.feature
|
@@ -195,6 +206,8 @@ test_files:
|
|
195
206
|
- features/step_definitions/jschematic_steps.rb
|
196
207
|
- features/support/env.rb
|
197
208
|
- features/type.feature
|
209
|
+
- spec/jschematic/attributes/disallow_spec.rb
|
210
|
+
- spec/jschematic/attributes/divisible_by_spec.rb
|
198
211
|
- spec/jschematic/attributes/enum_spec.rb
|
199
212
|
- spec/jschematic/attributes/format_spec.rb
|
200
213
|
- spec/jschematic/attributes/max_items_spec.rb
|