json_validation 0.1.0

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.gitmodules +3 -0
  4. data/CODE_OF_CONDUCT.md +49 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +60 -0
  8. data/Rakefile +6 -0
  9. data/json_validator.gemspec +24 -0
  10. data/lib/json_validation.rb +131 -0
  11. data/lib/json_validation/validator_collection.rb +17 -0
  12. data/lib/json_validation/validators/additional_items.rb +34 -0
  13. data/lib/json_validation/validators/additional_properties.rb +37 -0
  14. data/lib/json_validation/validators/all_of.rb +17 -0
  15. data/lib/json_validation/validators/any_of.rb +17 -0
  16. data/lib/json_validation/validators/default.rb +11 -0
  17. data/lib/json_validation/validators/dependencies.rb +36 -0
  18. data/lib/json_validation/validators/enum.rb +11 -0
  19. data/lib/json_validation/validators/exclusive_maximum.rb +11 -0
  20. data/lib/json_validation/validators/exclusive_minimum.rb +11 -0
  21. data/lib/json_validation/validators/format.rb +15 -0
  22. data/lib/json_validation/validators/items.rb +32 -0
  23. data/lib/json_validation/validators/max_items.rb +11 -0
  24. data/lib/json_validation/validators/max_length.rb +11 -0
  25. data/lib/json_validation/validators/max_properties.rb +11 -0
  26. data/lib/json_validation/validators/maximum.rb +15 -0
  27. data/lib/json_validation/validators/min_items.rb +11 -0
  28. data/lib/json_validation/validators/min_length.rb +11 -0
  29. data/lib/json_validation/validators/min_properties.rb +11 -0
  30. data/lib/json_validation/validators/minimum.rb +15 -0
  31. data/lib/json_validation/validators/multiple_of.rb +11 -0
  32. data/lib/json_validation/validators/not.rb +15 -0
  33. data/lib/json_validation/validators/one_of.rb +17 -0
  34. data/lib/json_validation/validators/pattern.rb +12 -0
  35. data/lib/json_validation/validators/pattern_properties.rb +22 -0
  36. data/lib/json_validation/validators/properties.rb +23 -0
  37. data/lib/json_validation/validators/ref.rb +20 -0
  38. data/lib/json_validation/validators/required.rb +11 -0
  39. data/lib/json_validation/validators/type.rb +15 -0
  40. data/lib/json_validation/validators/unique_items.rb +15 -0
  41. data/lib/json_validation/validators/validator.rb +28 -0
  42. data/lib/json_validation/version.rb +3 -0
  43. metadata +141 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bb93243d3878f2511489b948b8ce0594e528eb66
4
+ data.tar.gz: eb46537f761f494c9cb03fe6bd37e1308c1c7bec
5
+ SHA512:
6
+ metadata.gz: a9146a893fd8906483f03316d7a2b1172d67dedd9319dfb7fe2f6b56a047ad7fa5b675ae55dd4639b8a5c5359bc162400652b3ac68890154ee205525d21270c2
7
+ data.tar.gz: d876d70e4b5e3f110a40498f5a8afad032a89f3297944116f0c4a778b5b3d45428af2a98e3371dd180b36648c0fb96a774858521fe72b67ade723a69467a30fa
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -0,0 +1,3 @@
1
+ [submodule "test/json-schema-test-suite"]
2
+ path = test/json-schema-test-suite
3
+ url = git@github.com:json-schema/JSON-Schema-Test-Suite.git
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at peter.inglesby@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in json_validation.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'pry'
8
+ end
9
+
10
+ group :test do
11
+ gem 'mocha'
12
+ gem 'minitest'
13
+ gem 'minitest-reporters'
14
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Peter Inglesby
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # JsonValidation
2
+
3
+ JsonValidation validates JSON according to a [JSON Schema](http://json-schema.org/documentation.html).
4
+
5
+ It is designed to validate as quickly as possible.
6
+
7
+
8
+ ## Current limitations
9
+
10
+ * The library can only say whether a record is valid or not. In the event that
11
+ a record is not valid, it will not say why.
12
+ * The library will only validate against draft v4 of the JSON Schema
13
+ specification.
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ gem 'json_validation'
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install json_validation
29
+
30
+
31
+ ## Usage
32
+
33
+ Load the library:
34
+
35
+ require "json_validation"
36
+
37
+ Build a validator from a hash representing a JSON schema:
38
+
39
+ validator = JsonValidation.build_validator(schema)
40
+
41
+ Load a validator from a schema at a URL or path:
42
+
43
+ validator = JsonValidation.load_validator(uri)
44
+
45
+ Use the validator to validate whether a record validates against a schema.
46
+
47
+ validator.validate(record)
48
+ # => returns true or false
49
+
50
+
51
+ ## Contributing
52
+
53
+ If you find an example of a record being incorrectly validated against a
54
+ schema, please raise an issue on GitHub.
55
+
56
+ You can run the tests with:
57
+
58
+ $ bundle exec rake test
59
+
60
+ A handful of tests require internet access.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'json_validation/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "json_validation"
8
+ spec.version = JsonValidation::VERSION
9
+ spec.authors = ["Peter Inglesby"]
10
+ spec.email = ["peter.inglesby@gmail.com"]
11
+
12
+ spec.summary = "JsonValidation validates JSON according to a JSON Schema."
13
+ spec.homepage = "http://github.com/inglesp/json_validation"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.11"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_dependency "addressable"
23
+ spec.add_development_dependency "minitest", "~> 5.0"
24
+ end
@@ -0,0 +1,131 @@
1
+ require 'bigdecimal'
2
+ require 'json'
3
+ require 'open-uri'
4
+
5
+ require 'addressable/uri'
6
+
7
+ require 'json_validation/validator_collection'
8
+ require 'json_validation/validators/validator'
9
+ Dir[File.join(File.dirname(__FILE__), 'json_validation', 'validators', '*.rb')].each do |path|
10
+ require path
11
+ end
12
+ require 'json_validation/version'
13
+
14
+ module JsonValidation
15
+ extend self
16
+
17
+ TYPES_TO_CLASSES = {
18
+ :array => [Array],
19
+ :boolean => [TrueClass, FalseClass],
20
+ :integer => [Integer],
21
+ :number => [Numeric],
22
+ :null => [NilClass],
23
+ :object => [Hash],
24
+ :string => [String],
25
+ :any => [Object],
26
+ }
27
+
28
+ def load_validator(uri)
29
+ uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
30
+
31
+ schema = load_schema(uri)
32
+ build_validator(schema, uri)
33
+ end
34
+
35
+ def build_validator(schema, base_uri = nil)
36
+ if base_uri.nil?
37
+ base_uri = generate_uri(schema)
38
+ schema_cache[base_uri] = schema
39
+ end
40
+
41
+ if schema["id"]
42
+ base_uri = base_uri.join(Addressable::URI.parse(schema["id"]))
43
+ end
44
+
45
+ validators = schema.keys.map {|key|
46
+ if key == '$ref'
47
+ validator_name = 'Ref'
48
+ else
49
+ validator_name = key[0].upcase + key[1..-1]
50
+ end
51
+
52
+ begin
53
+ klass = JsonValidation::Validators.const_get(:"#{validator_name}")
54
+ rescue NameError
55
+ nil
56
+ else
57
+ klass.new(schema, base_uri)
58
+ end
59
+ }.compact
60
+
61
+ ValidatorCollection.new(validators)
62
+ end
63
+
64
+ def generate_uri(schema)
65
+ Addressable::URI.parse(Digest::SHA1.hexdigest(schema.to_json))
66
+ end
67
+
68
+ def load_schema(uri)
69
+ raise unless uri.is_a?(Addressable::URI)
70
+
71
+ uri = uri.clone
72
+ uri_fragment = uri.fragment
73
+ uri.fragment = nil
74
+ schema = schema_cache[uri]
75
+
76
+ return schema if uri_fragment == "" || uri_fragment.nil?
77
+
78
+ fragment = schema
79
+
80
+ uri_fragment[1..-1].split('/').each do |element|
81
+ element = element.gsub('~0', '~').gsub('~1', '/').gsub('%25', '%')
82
+
83
+ case fragment
84
+ when Hash
85
+ if fragment.has_key?(element)
86
+ fragment = fragment[element]
87
+ next
88
+ end
89
+ when Array
90
+ begin
91
+ ix = Integer(element)
92
+ if ix < fragment.size
93
+ fragment = fragment[ix]
94
+ next
95
+ end
96
+ rescue ArgumentError
97
+ end
98
+ else
99
+ raise "Could not look up #{uri_fragment} in #{schema}"
100
+ end
101
+ end
102
+
103
+ fragment
104
+ end
105
+
106
+ def clear_schema_cache
107
+ @schema_cache = nil
108
+ end
109
+
110
+ def schema_cache
111
+ @schema_cache ||= Hash.new {|cache, uri|
112
+ cache[uri] = JSON.parse(open(uri).read)
113
+ }
114
+ end
115
+
116
+ def get_format_validator(key)
117
+ format_validators.fetch(key).new
118
+ end
119
+
120
+ def add_format_validator(key, format_validator)
121
+ format_validators[key] = format_validator
122
+ end
123
+
124
+ def clear_format_validators
125
+ @format_validators = nil
126
+ end
127
+
128
+ def format_validators
129
+ @format_validators ||= {}
130
+ end
131
+ end
@@ -0,0 +1,17 @@
1
+ module JsonValidation
2
+ class ValidatorCollection
3
+ def initialize(validators)
4
+ @validators = validators
5
+ end
6
+
7
+ def validate(record)
8
+ @validators.all? {|validator|
9
+ if TYPES_TO_CLASSES[validator.class.type].any? {|klass| record.is_a?(klass)}
10
+ validator.validate(record)
11
+ else
12
+ true
13
+ end
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class AdditionalItems < Validator
4
+ type :array
5
+
6
+ def validate(record)
7
+ if !fragment.has_key?('items') || fragment['items'].is_a?(Hash)
8
+ true
9
+ else
10
+ case fragment['additionalItems']
11
+ when true
12
+ true
13
+ when false
14
+ find_additional_items(fragment, record).empty?
15
+ when Hash
16
+ find_additional_items(fragment, record).all? {|item|
17
+ inner_validator.validate(item)
18
+ }
19
+ else
20
+ raise "Unexpected type for fragment['additionalItems']"
21
+ end
22
+ end
23
+ end
24
+
25
+ def inner_validator
26
+ @inner_validator ||= build_validator(fragment["additionalItems"])
27
+ end
28
+
29
+ def find_additional_items(fragment, record)
30
+ record.drop(fragment['items'].size)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class AdditionalProperties < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ case fragment['additionalProperties']
8
+ when true
9
+ true
10
+ when false
11
+ find_additional_properties(fragment, record).empty?
12
+ when Hash
13
+ find_additional_properties(fragment, record).values.all? {|value|
14
+ inner_validator.validate(value)
15
+ }
16
+ else
17
+ raise "Unexpected type for fragment['additionalProperties']"
18
+ end
19
+ end
20
+
21
+ def inner_validator
22
+ @inner_validator ||= build_validator(fragment["additionalProperties"])
23
+ end
24
+
25
+ def find_additional_properties(fragment, record)
26
+ record.reject {|k, v|
27
+ fragment.fetch('properties', {}).keys.include?(k)
28
+ }.reject {|k, v|
29
+ fragment.fetch('patternProperties', {}).keys.any? {|pattern|
30
+ rx = Regexp.new(pattern)
31
+ rx.match(k)
32
+ }
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class AllOf < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ inner_validators.all? {|validator| validator.validate(record)}
8
+ end
9
+
10
+ def inner_validators
11
+ @inner_validators ||= fragment["allOf"].map {|f|
12
+ build_validator(f)
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class AnyOf < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ inner_validators.any? {|validator| validator.validate(record)}
8
+ end
9
+
10
+ def inner_validators
11
+ @inner_validators ||= fragment["anyOf"].map {|f|
12
+ build_validator(f)
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Default < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ true
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Dependencies < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ fragment['dependencies'].all? {|property, v|
8
+ case v
9
+ when Hash
10
+ dependency_fragment = v
11
+ if record.has_key?(property)
12
+ inner_validators[property].validate(record)
13
+ else
14
+ true
15
+ end
16
+ when Array
17
+ property_set = v
18
+ if record.has_key?(property)
19
+ property_set.all? {|p| record.has_key?(p)}
20
+ else
21
+ true
22
+ end
23
+ else
24
+ raise "Unexpected type for fragment['dependencies']['#{property}']"
25
+ end
26
+ }
27
+ end
28
+
29
+ def inner_validators
30
+ @inner_validators ||= Hash[fragment['dependencies'].map {|k, f|
31
+ [k, build_validator(f)]
32
+ }]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Enum < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ fragment['enum'].include?(record)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class ExclusiveMaximum < Validator
4
+ type :number
5
+
6
+ def validate(record)
7
+ true # no-op (handled by Maximum)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class ExclusiveMinimum < Validator
4
+ type :number
5
+
6
+ def validate(record)
7
+ true # no-op (handled by Minimum)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Format < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ inner_validator.validate(record)
8
+ end
9
+
10
+ def inner_validator
11
+ @inner_validator ||= JsonValidation.get_format_validator(fragment["format"])
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Items < Validator
4
+ type :array
5
+
6
+ def validate(record)
7
+ case fragment['items']
8
+ when Hash
9
+ record.all? {|item| inner_validator.validate(item)}
10
+ when Array
11
+ inner_validators.zip(record).all? {|validator, item|
12
+ validator.validate(item)
13
+ }
14
+ else
15
+ raise "Unexpected type for fragment['items']"
16
+ end
17
+ end
18
+
19
+ def inner_validator
20
+ raise unless fragment["items"].is_a?(Hash)
21
+ @inner_validator ||= build_validator(fragment["items"])
22
+ end
23
+
24
+ def inner_validators
25
+ raise unless fragment["items"].is_a?(Array)
26
+ @inner_validators ||= fragment["items"].map {|f|
27
+ build_validator(f)
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MaxItems < Validator
4
+ type :array
5
+
6
+ def validate(record)
7
+ fragment['maxItems'] >= record.size
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MaxLength < Validator
4
+ type :string
5
+
6
+ def validate(record)
7
+ fragment['maxLength'] >= record.size
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MaxProperties < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ fragment['maxProperties'] >= record.size
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Maximum < Validator
4
+ type :number
5
+
6
+ def validate(record)
7
+ if fragment['exclusiveMaximum']
8
+ fragment['maximum'] > record
9
+ else
10
+ fragment['maximum'] >= record
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MinItems < Validator
4
+ type :array
5
+
6
+ def validate(record)
7
+ fragment['minItems'] <= record.size
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MinLength < Validator
4
+ type :string
5
+
6
+ def validate(record)
7
+ fragment['minLength'] <= record.size
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MinProperties < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ fragment['minProperties'] <= record.size
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Minimum < Validator
4
+ type :number
5
+
6
+ def validate(record)
7
+ if fragment['exclusiveMinimum']
8
+ fragment['minimum'] < record
9
+ else
10
+ fragment['minimum'] <= record
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class MultipleOf < Validator
4
+ type :number
5
+
6
+ def validate(record)
7
+ BigDecimal.new(record.to_s) % BigDecimal.new(fragment['multipleOf'].to_s) == 0
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Not < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ !inner_validator.validate(record)
8
+ end
9
+
10
+ def inner_validator
11
+ @inner_validator ||= build_validator(fragment["not"])
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class OneOf < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ inner_validators.count {|validator| validator.validate(record)} == 1
8
+ end
9
+
10
+ def inner_validators
11
+ @inner_validators ||= fragment["oneOf"].map {|f|
12
+ build_validator(f)
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Pattern < Validator
4
+ type :string
5
+
6
+ def validate(record)
7
+ rx = Regexp.new(fragment['pattern'])
8
+ !!rx.match(record)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class PatternProperties < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ fragment['patternProperties'].keys.all? {|pattern|
8
+ rx = Regexp.new(pattern)
9
+ record.select {|k, v| rx.match(k)}.all? {|k, v|
10
+ inner_validators[pattern].validate(v)
11
+ }
12
+ }
13
+ end
14
+
15
+ def inner_validators
16
+ @inner_validators ||= Hash[fragment['patternProperties'].map {|pattern, f|
17
+ [pattern, build_validator(f)]
18
+ }]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Properties < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ fragment['properties'].keys.all? {|key|
8
+ if record[key]
9
+ inner_validators[key].validate(record[key])
10
+ else
11
+ true
12
+ end
13
+ }
14
+ end
15
+
16
+ def inner_validators
17
+ @inner_validators ||= Hash[fragment['properties'].map {|k, f|
18
+ [k, build_validator(f)]
19
+ }]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Ref < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ inner_validator.validate(record)
8
+ end
9
+
10
+ def inner_validator
11
+ return @inner_validator if @inner_validator
12
+
13
+ path = fragment['$ref']
14
+ reffed_uri = base_uri.join(Addressable::URI.parse(path))
15
+ reffed_schema = JsonValidation.load_schema(reffed_uri)
16
+ @inner_validator = build_validator_with_new_base_uri(reffed_schema, reffed_uri)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Required < Validator
4
+ type :object
5
+
6
+ def validate(record)
7
+ fragment['required'].all? {|element| record.has_key?(element)}
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Type < Validator
4
+ type :any
5
+
6
+ def validate(record)
7
+ types = Array(fragment['type'])
8
+ types.any? {|type|
9
+ klasses = JsonValidation::TYPES_TO_CLASSES.fetch(type.to_sym)
10
+ klasses.any? {|klass| record.is_a?(klass)}
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class UniqueItems < Validator
4
+ type :array
5
+
6
+ def validate(record)
7
+ if fragment['uniqueItems']
8
+ record.size == record.uniq.size
9
+ else
10
+ true
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module JsonValidation
2
+ module Validators
3
+ class Validator
4
+ def self.type(type=nil)
5
+ if type.nil?
6
+ @type
7
+ else
8
+ @type = type
9
+ end
10
+ end
11
+
12
+ attr_reader :fragment, :base_uri
13
+
14
+ def initialize(fragment, base_uri)
15
+ @fragment = fragment
16
+ @base_uri = base_uri
17
+ end
18
+
19
+ def build_validator(fragment)
20
+ JsonValidation.build_validator(fragment, base_uri)
21
+ end
22
+
23
+ def build_validator_with_new_base_uri(fragment, base_uri)
24
+ JsonValidation.build_validator(fragment, base_uri)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module JsonValidation
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json_validation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Inglesby
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: addressable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description:
70
+ email:
71
+ - peter.inglesby@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".gitmodules"
78
+ - CODE_OF_CONDUCT.md
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - json_validator.gemspec
84
+ - lib/json_validation.rb
85
+ - lib/json_validation/validator_collection.rb
86
+ - lib/json_validation/validators/additional_items.rb
87
+ - lib/json_validation/validators/additional_properties.rb
88
+ - lib/json_validation/validators/all_of.rb
89
+ - lib/json_validation/validators/any_of.rb
90
+ - lib/json_validation/validators/default.rb
91
+ - lib/json_validation/validators/dependencies.rb
92
+ - lib/json_validation/validators/enum.rb
93
+ - lib/json_validation/validators/exclusive_maximum.rb
94
+ - lib/json_validation/validators/exclusive_minimum.rb
95
+ - lib/json_validation/validators/format.rb
96
+ - lib/json_validation/validators/items.rb
97
+ - lib/json_validation/validators/max_items.rb
98
+ - lib/json_validation/validators/max_length.rb
99
+ - lib/json_validation/validators/max_properties.rb
100
+ - lib/json_validation/validators/maximum.rb
101
+ - lib/json_validation/validators/min_items.rb
102
+ - lib/json_validation/validators/min_length.rb
103
+ - lib/json_validation/validators/min_properties.rb
104
+ - lib/json_validation/validators/minimum.rb
105
+ - lib/json_validation/validators/multiple_of.rb
106
+ - lib/json_validation/validators/not.rb
107
+ - lib/json_validation/validators/one_of.rb
108
+ - lib/json_validation/validators/pattern.rb
109
+ - lib/json_validation/validators/pattern_properties.rb
110
+ - lib/json_validation/validators/properties.rb
111
+ - lib/json_validation/validators/ref.rb
112
+ - lib/json_validation/validators/required.rb
113
+ - lib/json_validation/validators/type.rb
114
+ - lib/json_validation/validators/unique_items.rb
115
+ - lib/json_validation/validators/validator.rb
116
+ - lib/json_validation/version.rb
117
+ homepage: http://github.com/inglesp/json_validation
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.4.5
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: JsonValidation validates JSON according to a JSON Schema.
141
+ test_files: []