jschematic 0.0.6 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jschematic (0.0.5)
4
+ jschematic (0.0.6)
5
5
  addressable
6
6
 
7
7
  GEM
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 v3 Validator for Ruby.
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
- It is currently pre-release software. The basics work fairly well, but
6
- it is a work in progress.
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
- Most of the core schema definition is supported with these exceptions:
10
+ ## Status
9
11
 
10
- * $schema
11
- * extends
12
- * divisibleBy
13
- * disallow
12
+ Core schema: fully supported
13
+ Hyper schema: not supported
14
14
 
15
- In addition to this, only DateTime, Date, IPv4, IPv6 and URI formats are currently
16
- implemented.
15
+ The format attribute supports only these formats:
17
16
 
18
- Please report any bugs you find in the issue tracker here:
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 consulting in those cases where cross-schema
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,17 @@
1
+ Feature: Core schema: divisibleBy
2
+ Scenario: No remainder
3
+ Given the schema is:
4
+ """
5
+ {
6
+ "divisibleBy": 2
7
+ }
8
+ """
9
+ Then these are valid JSON:
10
+ | 0 |
11
+ | 2 |
12
+ | 42.0 |
13
+ But these are not valid JSON:
14
+ | 0.1 |
15
+ | 1 |
16
+ | 13 |
17
+
@@ -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
+
@@ -84,6 +84,7 @@ Feature: Core schema: format
84
84
  | "2011-02-27" |
85
85
  | "1980-02-29" |
86
86
  But these are not valid JSON:
87
- | "1981-02-29" |
88
- | "August 1st, 1986" |
87
+ | "1981-02-29" |
88
+ | "August 1st, 1986" |
89
+ | "1980-02-29T08:51:32Z" |
89
90
 
data/features/ref.feature CHANGED
@@ -135,4 +135,3 @@ Feature: Core schema: $ref
135
135
  ]
136
136
  """
137
137
 
138
- Scenario: Ref appears before the id it references
@@ -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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jschematic'
3
- s.version = '0.0.6'
3
+ s.version = '0.0.9'
4
4
  s.authors = ["Mike Sassak"]
5
5
  s.description = "JSON Schema v3 Validator"
6
6
  s.summary = "jschematic #{s.version}"
data/lib/jschematic.rb CHANGED
@@ -8,6 +8,11 @@ module Jschematic
8
8
  end
9
9
 
10
10
  def self.validate!(instance, schema, opts={})
11
+ self.debug = opts[:debug]
11
12
  Context.new(*opts[:context]).validate!(instance, schema)
12
13
  end
14
+
15
+ class << self
16
+ attr_accessor :debug
17
+ end
13
18
  end
@@ -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
@@ -69,6 +69,7 @@ module Jschematic
69
69
  include Jschematic::Element
70
70
 
71
71
  def accepts?(date)
72
+ raise ArgumentError unless date =~ /^\d{4}-\d{2}-\d{2}$/
72
73
  ::Date.strptime(date)
73
74
  rescue ArgumentError
74
75
  false
@@ -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 maximum
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 minimum
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([Float, Integer], instance)
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
@@ -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
- # Not finding an attribute is not necessarily an error, but this is
58
- # obviously not the right way to handle it. Need to find a better way to
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
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ module Jschematic
4
+ module Attributes
5
+ describe DivisibleBy do
6
+ subject { DivisibleBy.new(2.0) }
7
+ it { should accept("a string") }
8
+ it { should accept("1.2345") }
9
+ it { should accept([1,2,3]) }
10
+ end
11
+ end
12
+ 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
- - 6
9
- version: 0.0.6
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-03-15 00:00:00 -05:00
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.6
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