simple_json_schema 0.1.3

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.
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module Validators
5
+ module Concerns
6
+ module Format
7
+ # this is no good
8
+ EMAIL_REGEX = /\A[^@\s]+@([\p{L}\d-]+\.)+[\p{L}\d\-]{2,}\z/i.freeze
9
+ LABEL_REGEX_STRING = '[\p{L}\p{N}]([\p{L}\p{N}\-]*[\p{L}\p{N}])?'
10
+ HOSTNAME_REGEX = /\A(#{LABEL_REGEX_STRING}\.)*#{LABEL_REGEX_STRING}\z/i.freeze
11
+ JSON_POINTER_REGEX_STRING = '(\/([^~\/]|~[01])*)*'
12
+ JSON_POINTER_REGEX = /\A#{JSON_POINTER_REGEX_STRING}\z/.freeze
13
+ RELATIVE_JSON_POINTER_REGEX = /\A(0|[1-9]\d*)(#|#{JSON_POINTER_REGEX_STRING})?\z/.freeze
14
+ DATE_TIME_OFFSET_REGEX = /(Z|[+\-]([01][0-9]|2[0-3]):[0-5][0-9])\z/i.freeze
15
+ INVALID_QUERY_REGEX = /[[:space:]]/.freeze
16
+ ASCII_REGEX = /[^[:ascii:]]/.freeze
17
+
18
+ def valid_format(scope)
19
+ format = scope[:format]
20
+ return if format.nil?
21
+ return if valid_spec_format?(scope.value, format)
22
+
23
+ scope.error(:format)
24
+ end
25
+
26
+ private
27
+
28
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
29
+ def valid_spec_format?(value, format)
30
+ case format
31
+ when 'date-time'
32
+ valid_date_time?(value)
33
+ when 'date'
34
+ valid_date_time?("#{value}T04:05:06.123456789+07:00")
35
+ when 'time'
36
+ valid_date_time?("2001-02-03T#{value}")
37
+ when 'email'
38
+ value.ascii_only? && valid_email?(value)
39
+ when 'idn-email'
40
+ valid_email?(value)
41
+ when 'hostname'
42
+ value.ascii_only? && valid_hostname?(value)
43
+ when 'idn-hostname'
44
+ valid_hostname?(value)
45
+ when 'ipv4'
46
+ valid_ip?(value, :v4)
47
+ when 'ipv6'
48
+ valid_ip?(value, :v6)
49
+ when 'uri'
50
+ valid_uri?(value)
51
+ when 'uri-reference'
52
+ valid_uri_reference?(value)
53
+ when 'iri'
54
+ valid_uri?(iri_escape(value))
55
+ when 'iri-reference'
56
+ valid_uri_reference?(iri_escape(value))
57
+ # when 'uri-template'
58
+ # valid_uri_template?(value)
59
+ when 'json-pointer'
60
+ JSON_POINTER_REGEX.match?(value)
61
+ when 'relative-json-pointer'
62
+ RELATIVE_JSON_POINTER_REGEX.match?(value)
63
+ when 'regex'
64
+ EcmaReValidator.valid?(value)
65
+ end
66
+ end
67
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
68
+
69
+ def valid_date_time?(value)
70
+ DateTime.rfc3339(value)
71
+ DATE_TIME_OFFSET_REGEX.match?(value)
72
+ rescue ArgumentError => e
73
+ raise e unless e.message == 'invalid date'
74
+
75
+ false
76
+ end
77
+
78
+ def valid_email?(value)
79
+ EMAIL_REGEX.match?(value)
80
+ end
81
+
82
+ def valid_hostname?(value)
83
+ HOSTNAME_REGEX.match?(value) && value.split('.').all? { |label| label.size <= 63 }
84
+ end
85
+
86
+ def valid_ip?(value, type)
87
+ ip_address = IPAddr.new(value)
88
+ type == :v4 ? ip_address.ipv4? : ip_address.ipv6?
89
+ rescue IPAddr::InvalidAddressError
90
+ false
91
+ end
92
+
93
+ def parse_uri_scheme(value)
94
+ scheme, _, _, _, _, _, opaque, query, = URI::RFC3986_PARSER.split(value)
95
+ # URI::RFC3986_PARSER.parse allows spaces in these and I don't think it should
96
+ raise URI::InvalidURIError if INVALID_QUERY_REGEX.match?(query) || INVALID_QUERY_REGEX.match?(opaque)
97
+
98
+ scheme
99
+ end
100
+
101
+ def valid_uri?(value)
102
+ !parse_uri_scheme(value).nil?
103
+ rescue URI::InvalidURIError
104
+ false
105
+ end
106
+
107
+ def valid_uri_reference?(value)
108
+ parse_uri_scheme(value)
109
+ true
110
+ rescue URI::InvalidURIError
111
+ false
112
+ end
113
+
114
+ def iri_escape(value)
115
+ value.gsub(ASCII_REGEX) do |match|
116
+ us = match
117
+ tmp = +''
118
+ us.each_byte do |uc|
119
+ tmp << format('%%%02X', uc)
120
+ end
121
+ tmp
122
+ end.force_encoding(Encoding::US_ASCII)
123
+ end
124
+
125
+ # def valid_uri_template?(value)
126
+ # Addressable::Template.new(value)
127
+ # true
128
+ # rescue Addressable::InvalidURIError
129
+ # false
130
+ # end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module Validators
5
+ class Integer < Numeric
6
+ INTEGER_FORMAT = /\A-?\d+\Z/.freeze
7
+
8
+ def validate(scope)
9
+ value = scope.value
10
+
11
+ return scope.error(:integer) if !value.is_a?(::Numeric) || (!value.is_a?(::Integer) && value.floor != value)
12
+
13
+ super
14
+ end
15
+
16
+ def casting(value)
17
+ value.to_i if value.is_a?(::String) && INTEGER_FORMAT.match?(value)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module Validators
5
+ class Null < Base
6
+ def validate(scope)
7
+ scope.error(:null) unless scope.value.nil?
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module Validators
5
+ class Number < Numeric
6
+ FLOAT_FORMAT = /\A-?\d+\.\d+\Z/.freeze
7
+
8
+ def validate(scope)
9
+ value = scope.value
10
+
11
+ return scope.error(:number) unless value.is_a?(::Numeric)
12
+
13
+ super
14
+ end
15
+
16
+ def casting(value)
17
+ BigDecimal(value) if value.is_a?(::String) && FLOAT_FORMAT.match?(value)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module Validators
5
+ class Numeric < Base
6
+ def validate(scope)
7
+ value = scope.value
8
+
9
+ Checker.at_value(scope, :maximum, :>)
10
+ Checker.at_value(scope, :minimum, :<)
11
+ Checker.at_value(scope, :exclusiveMaximum, :>=)
12
+ Checker.at_value(scope, :exclusiveMinimum, :<=)
13
+
14
+ multiple_of = scope[:multipleOf]
15
+ return unless multiple_of
16
+
17
+ quotient = value / multiple_of.to_f
18
+ scope.error(:multipleOf) unless quotient.floor == quotient
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ module Validators
5
+ class String < Base
6
+ include Concerns::Format
7
+
8
+ def validate(scope)
9
+ value = scope.value
10
+
11
+ return scope.error(:string) unless value.is_a?(::String)
12
+
13
+ Checker.at_size(scope, :maxLength, :>)
14
+ Checker.at_size(scope, :minLength, :<)
15
+
16
+ valid_pattern(scope)
17
+ valid_format(scope)
18
+ end
19
+
20
+ private
21
+
22
+ def valid_pattern(scope)
23
+ pattern = scope[:pattern]
24
+ return if pattern.nil?
25
+
26
+ match = RegexHelper.ecma_262_regex(pattern, scope.cache).match?(scope.value)
27
+ return if match
28
+
29
+ scope.error(:pattern)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleJSONSchema
4
+ VERSION = '0.1.3'
5
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/simple_json_schema/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'simple_json_schema'
7
+ spec.version = SimpleJSONSchema::VERSION
8
+ spec.authors = ['Georgeo Rocco']
9
+ spec.email = ['ggrocco@vliper.com']
10
+
11
+ spec.description = 'Simple JSON Schema validator. Supports draft 7 partial,
12
+ based on https://github.com/davishmcclurg/json_schemer'
13
+ spec.summary = <<-SUMMARY
14
+ This implementation of the JSON Schema validation is based on the
15
+ https://github.com/davishmcclurg/json_schemer) (whit is the recommended to be used),
16
+ but only implement the Draft7
17
+ SUMMARY
18
+ spec.homepage = 'https://gitlab.com/vliper/simple_json_schema'
19
+ spec.license = 'MIT'
20
+
21
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
22
+
23
+ spec.metadata['homepage_uri'] = spec.homepage
24
+ spec.metadata['source_code_uri'] = spec.homepage
25
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
26
+
27
+ # Specify which files should be added to the gem when it is released.
28
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
30
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
+ end
32
+ spec.bindir = 'exe'
33
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ['lib']
35
+
36
+ spec.add_dependency 'activesupport', '~> 6.0'
37
+ spec.add_dependency 'addressable', '~> 2.7'
38
+ spec.add_dependency 'ecma-re-validator', '~> 0.3'
39
+ spec.add_dependency 'regexp_parser', '~> 2.0'
40
+
41
+ spec.add_development_dependency 'pry-byebug', '~> 3.9'
42
+ spec.add_development_dependency 'rake', '~> 13.0'
43
+ spec.add_development_dependency 'rspec', '~> 3.10'
44
+ spec.add_development_dependency 'rubocop', '~> 1.6'
45
+ spec.add_development_dependency 'rubocop-performance', '~> 1.9'
46
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.1'
47
+ spec.add_development_dependency 'simplecov', '~> 0.20'
48
+ end
metadata ADDED
@@ -0,0 +1,234 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_json_schema
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Georgeo Rocco
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ecma-re-validator
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: regexp_parser
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.9'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.10'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-performance
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.9'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.9'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.1'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2.1'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.20'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.20'
167
+ description: |-
168
+ Simple JSON Schema validator. Supports draft 7 partial,
169
+ based on https://github.com/davishmcclurg/json_schemer
170
+ email:
171
+ - ggrocco@vliper.com
172
+ executables: []
173
+ extensions: []
174
+ extra_rdoc_files: []
175
+ files:
176
+ - ".editorconfig"
177
+ - ".gitignore"
178
+ - ".gitlab-ci.yml"
179
+ - ".gitmodules"
180
+ - ".rspec"
181
+ - ".rubocop.yml"
182
+ - CODE_OF_CONDUCT.md
183
+ - Gemfile
184
+ - Gemfile.lock
185
+ - LICENSE.txt
186
+ - README.md
187
+ - Rakefile
188
+ - bin/console
189
+ - bin/setup
190
+ - lib/simple_json_schema.rb
191
+ - lib/simple_json_schema/checker.rb
192
+ - lib/simple_json_schema/concerns/hash_acessor.rb
193
+ - lib/simple_json_schema/items_helper.rb
194
+ - lib/simple_json_schema/properties_helper.rb
195
+ - lib/simple_json_schema/regex_helper.rb
196
+ - lib/simple_json_schema/scope.rb
197
+ - lib/simple_json_schema/validator.rb
198
+ - lib/simple_json_schema/validators/base.rb
199
+ - lib/simple_json_schema/validators/boolean.rb
200
+ - lib/simple_json_schema/validators/concerns/format.rb
201
+ - lib/simple_json_schema/validators/integer.rb
202
+ - lib/simple_json_schema/validators/null.rb
203
+ - lib/simple_json_schema/validators/number.rb
204
+ - lib/simple_json_schema/validators/numeric.rb
205
+ - lib/simple_json_schema/validators/string.rb
206
+ - lib/simple_json_schema/version.rb
207
+ - simple_json_schema.gemspec
208
+ homepage: https://gitlab.com/vliper/simple_json_schema
209
+ licenses:
210
+ - MIT
211
+ metadata:
212
+ homepage_uri: https://gitlab.com/vliper/simple_json_schema
213
+ source_code_uri: https://gitlab.com/vliper/simple_json_schema
214
+ post_install_message:
215
+ rdoc_options: []
216
+ require_paths:
217
+ - lib
218
+ required_ruby_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 2.6.0
223
+ required_rubygems_version: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - ">="
226
+ - !ruby/object:Gem::Version
227
+ version: '0'
228
+ requirements: []
229
+ rubygems_version: 3.1.4
230
+ signing_key:
231
+ specification_version: 4
232
+ summary: This implementation of the JSON Schema validation is based on the https://github.com/davishmcclurg/json_schemer)
233
+ (whit is the recommended to be used), but only implement the Draft7
234
+ test_files: []