json_validation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []