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 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