jsi 0.2.0 → 0.6.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.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +36 -0
- data/LICENSE.md +613 -0
- data/README.md +153 -52
- data/lib/jsi/base.rb +485 -338
- data/lib/jsi/jsi_coder.rb +24 -18
- data/lib/jsi/metaschema.rb +7 -0
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +100 -0
- data/lib/jsi/metaschema_node.rb +245 -0
- data/lib/jsi/pathed_node.rb +49 -46
- data/lib/jsi/ptr.rb +292 -0
- data/lib/jsi/schema/application/child_application/contains.rb +16 -0
- data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
- data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
- data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
- data/lib/jsi/schema/application/child_application/items.rb +18 -0
- data/lib/jsi/schema/application/child_application/properties.rb +25 -0
- data/lib/jsi/schema/application/child_application.rb +40 -0
- data/lib/jsi/schema/application/draft04.rb +8 -0
- data/lib/jsi/schema/application/draft06.rb +8 -0
- data/lib/jsi/schema/application/draft07.rb +8 -0
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
- data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
- data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
- data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
- data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
- data/lib/jsi/schema/application/inplace_application/someof.rb +29 -0
- data/lib/jsi/schema/application/inplace_application.rb +46 -0
- data/lib/jsi/schema/application.rb +12 -0
- data/lib/jsi/schema/draft04.rb +14 -0
- data/lib/jsi/schema/draft06.rb +14 -0
- data/lib/jsi/schema/draft07.rb +14 -0
- data/lib/jsi/schema/issue.rb +36 -0
- data/lib/jsi/schema/ref.rb +159 -0
- data/lib/jsi/schema/schema_ancestor_node.rb +119 -0
- data/lib/jsi/schema/validation/array.rb +69 -0
- data/lib/jsi/schema/validation/const.rb +20 -0
- data/lib/jsi/schema/validation/contains.rb +25 -0
- data/lib/jsi/schema/validation/core.rb +39 -0
- data/lib/jsi/schema/validation/dependencies.rb +49 -0
- data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
- data/lib/jsi/schema/validation/draft04.rb +112 -0
- data/lib/jsi/schema/validation/draft06.rb +122 -0
- data/lib/jsi/schema/validation/draft07.rb +159 -0
- data/lib/jsi/schema/validation/enum.rb +25 -0
- data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
- data/lib/jsi/schema/validation/items.rb +54 -0
- data/lib/jsi/schema/validation/not.rb +20 -0
- data/lib/jsi/schema/validation/numeric.rb +121 -0
- data/lib/jsi/schema/validation/object.rb +45 -0
- data/lib/jsi/schema/validation/pattern.rb +34 -0
- data/lib/jsi/schema/validation/properties.rb +101 -0
- data/lib/jsi/schema/validation/property_names.rb +32 -0
- data/lib/jsi/schema/validation/ref.rb +40 -0
- data/lib/jsi/schema/validation/required.rb +27 -0
- data/lib/jsi/schema/validation/someof.rb +90 -0
- data/lib/jsi/schema/validation/string.rb +47 -0
- data/lib/jsi/schema/validation/type.rb +49 -0
- data/lib/jsi/schema/validation.rb +51 -0
- data/lib/jsi/schema.rb +528 -233
- data/lib/jsi/schema_classes.rb +238 -51
- data/lib/jsi/schema_registry.rb +141 -0
- data/lib/jsi/schema_set.rb +141 -0
- data/lib/jsi/simple_wrap.rb +8 -3
- data/lib/jsi/typelike_modules.rb +75 -68
- data/lib/jsi/util/attr_struct.rb +106 -0
- data/lib/jsi/util.rb +167 -64
- data/lib/jsi/validation/error.rb +34 -0
- data/lib/jsi/validation/result.rb +210 -0
- data/lib/jsi/validation.rb +15 -0
- data/lib/jsi/version.rb +3 -1
- data/lib/jsi.rb +72 -9
- data/lib/schemas/json-schema.org/draft-04/schema.rb +12 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +12 -0
- data/lib/schemas/json-schema.org/draft-07/schema.rb +12 -0
- data/readme.rb +138 -0
- data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
- data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
- data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
- metadata +80 -107
- data/.simplecov +0 -1
- data/LICENSE.txt +0 -21
- data/Rakefile.rb +0 -9
- data/jsi.gemspec +0 -31
- data/lib/jsi/base/to_rb.rb +0 -126
- data/lib/jsi/json/node.rb +0 -243
- data/lib/jsi/json/pointer.rb +0 -330
- data/lib/jsi/json-schema-fragments.rb +0 -59
- data/lib/jsi/json.rb +0 -8
- data/test/base_array_test.rb +0 -209
- data/test/base_hash_test.rb +0 -204
- data/test/base_test.rb +0 -422
- data/test/jsi_coder_test.rb +0 -85
- data/test/jsi_json_arraynode_test.rb +0 -150
- data/test/jsi_json_hashnode_test.rb +0 -132
- data/test/jsi_json_node_test.rb +0 -310
- data/test/jsi_json_pointer_test.rb +0 -106
- data/test/jsi_test.rb +0 -11
- data/test/jsi_typelike_as_json_test.rb +0 -53
- data/test/schema_test.rb +0 -196
- data/test/spreedly_openapi_test.rb +0 -8
- data/test/test_helper.rb +0 -63
- data/test/util_test.rb +0 -62
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
module Validation
|
|
5
|
+
Error = Util::AttrStruct[*%w(
|
|
6
|
+
message
|
|
7
|
+
keyword
|
|
8
|
+
schema
|
|
9
|
+
instance_ptr
|
|
10
|
+
instance_document
|
|
11
|
+
)]
|
|
12
|
+
|
|
13
|
+
# a validation error of a schema instance against a schema
|
|
14
|
+
#
|
|
15
|
+
# @!attribute message
|
|
16
|
+
# a message describing the error
|
|
17
|
+
# @return [String]
|
|
18
|
+
# @!attribute keyword
|
|
19
|
+
# the keyword of the schema which failed to validate.
|
|
20
|
+
# this may be absent if the error is not from a schema keyword (i.e, `false` schema).
|
|
21
|
+
# @return [String]
|
|
22
|
+
# @!attribute schema
|
|
23
|
+
# the schema against which the instance failed to validate
|
|
24
|
+
# @return [JSI::Schema]
|
|
25
|
+
# @!attribute instance_ptr
|
|
26
|
+
# pointer to the instance in instance_document
|
|
27
|
+
# @return [JSI::Ptr]
|
|
28
|
+
# @!attribute instance_document
|
|
29
|
+
# document containing the instance at instance_ptr
|
|
30
|
+
# @return [Object]
|
|
31
|
+
class Error
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
module Validation
|
|
5
|
+
# a result of validating an instance against schemas which describe it.
|
|
6
|
+
# virtual base class.
|
|
7
|
+
class Result
|
|
8
|
+
include Util::Virtual
|
|
9
|
+
|
|
10
|
+
Builder = Util::AttrStruct[*%w(
|
|
11
|
+
result
|
|
12
|
+
schema
|
|
13
|
+
instance_ptr
|
|
14
|
+
instance_document
|
|
15
|
+
validate_only
|
|
16
|
+
visited_refs
|
|
17
|
+
)]
|
|
18
|
+
|
|
19
|
+
# @private
|
|
20
|
+
# a structure used to build a Result. virtual base class.
|
|
21
|
+
class Builder
|
|
22
|
+
def instance
|
|
23
|
+
instance_ptr.evaluate(instance_document)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def schema_issue(*_)
|
|
27
|
+
virtual_method
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def schema_error(message, keyword = nil)
|
|
31
|
+
schema_issue(:error, message, keyword)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def schema_warning(message, keyword = nil)
|
|
35
|
+
schema_issue(:warning, message, keyword)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param subschema_ptr [JSI::Ptr, #to_ary]
|
|
39
|
+
# @return [JSI::Validation::Result]
|
|
40
|
+
def inplace_subschema_validate(subschema_ptr)
|
|
41
|
+
subresult = schema.subschema(subschema_ptr).internal_validate_instance(
|
|
42
|
+
instance_ptr,
|
|
43
|
+
instance_document,
|
|
44
|
+
validate_only: validate_only,
|
|
45
|
+
visited_refs: visited_refs,
|
|
46
|
+
)
|
|
47
|
+
merge_schema_issues(subresult)
|
|
48
|
+
subresult
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @param subschema_ptr [JSI::Ptr, #to_ary]
|
|
52
|
+
# @param subinstance_ptr [JSI::Ptr, #to_ary]
|
|
53
|
+
# @return [JSI::Validation::Result]
|
|
54
|
+
def child_subschema_validate(subschema_ptr, subinstance_ptr)
|
|
55
|
+
subresult = schema.subschema(subschema_ptr).internal_validate_instance(
|
|
56
|
+
instance_ptr + subinstance_ptr,
|
|
57
|
+
instance_document,
|
|
58
|
+
validate_only: validate_only,
|
|
59
|
+
)
|
|
60
|
+
merge_schema_issues(subresult)
|
|
61
|
+
subresult
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param other_result [JSI::Validation::Result]
|
|
65
|
+
# @return [void]
|
|
66
|
+
def merge_schema_issues(other_result)
|
|
67
|
+
unless validate_only
|
|
68
|
+
# schema_issues are always merged from subschema results (not depending on validation results)
|
|
69
|
+
result.schema_issues.merge(other_result.schema_issues)
|
|
70
|
+
end
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def builder(schema, instance_ptr, instance_document, validate_only, visited_refs)
|
|
76
|
+
self.class::Builder.new(
|
|
77
|
+
result: self,
|
|
78
|
+
schema: schema,
|
|
79
|
+
instance_ptr: instance_ptr,
|
|
80
|
+
instance_document: instance_document,
|
|
81
|
+
validate_only: validate_only,
|
|
82
|
+
visited_refs: visited_refs,
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# is the instance valid against its schemas?
|
|
87
|
+
# @return [Boolean]
|
|
88
|
+
def valid?
|
|
89
|
+
# :nocov:
|
|
90
|
+
virtual_method
|
|
91
|
+
# :nocov:
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
include Util::FingerprintHash
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# a full result of validating an instance against its schemas, with each validation error
|
|
98
|
+
class FullResult < Result
|
|
99
|
+
# @private
|
|
100
|
+
class Builder < Result::Builder
|
|
101
|
+
def validate(
|
|
102
|
+
valid,
|
|
103
|
+
message,
|
|
104
|
+
keyword: nil,
|
|
105
|
+
results: []
|
|
106
|
+
)
|
|
107
|
+
results.each { |res| result.schema_issues.merge(res.schema_issues) }
|
|
108
|
+
if !valid
|
|
109
|
+
results.each { |res| result.validation_errors.merge(res.validation_errors) }
|
|
110
|
+
result.validation_errors << Validation::Error.new({
|
|
111
|
+
message: message,
|
|
112
|
+
keyword: keyword,
|
|
113
|
+
schema: schema,
|
|
114
|
+
instance_ptr: instance_ptr,
|
|
115
|
+
instance_document: instance_document,
|
|
116
|
+
})
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def schema_issue(level, message, keyword = nil)
|
|
121
|
+
result.schema_issues << Schema::Issue.new({
|
|
122
|
+
level: level,
|
|
123
|
+
message: message,
|
|
124
|
+
keyword: keyword,
|
|
125
|
+
schema: schema,
|
|
126
|
+
})
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def initialize
|
|
131
|
+
@validation_errors = Set.new
|
|
132
|
+
@schema_issues = Set.new
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
attr_reader :validation_errors
|
|
136
|
+
attr_reader :schema_issues
|
|
137
|
+
|
|
138
|
+
def valid?
|
|
139
|
+
validation_errors.empty?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def freeze
|
|
143
|
+
@validation_errors.each(&:freeze)
|
|
144
|
+
@schema_issues.each(&:freeze)
|
|
145
|
+
@validation_errors.freeze
|
|
146
|
+
@schema_issues.freeze
|
|
147
|
+
super
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def merge(result)
|
|
151
|
+
unless result.is_a?(FullResult)
|
|
152
|
+
raise(TypeError, "not a #{FullResult.name}: #{result.pretty_inspect.chomp}")
|
|
153
|
+
end
|
|
154
|
+
validation_errors.merge(result.validation_errors)
|
|
155
|
+
schema_issues.merge(result.schema_issues)
|
|
156
|
+
self
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def +(result)
|
|
160
|
+
FullResult.new.merge(self).merge(result)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @private
|
|
164
|
+
def jsi_fingerprint
|
|
165
|
+
{
|
|
166
|
+
class: self.class,
|
|
167
|
+
validation_errors: validation_errors,
|
|
168
|
+
schema_issues: schema_issues,
|
|
169
|
+
}
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# a result indicating only whether an instance is valid against its schemas
|
|
174
|
+
class ValidityResult < Result
|
|
175
|
+
# @private
|
|
176
|
+
class Builder < Result::Builder
|
|
177
|
+
def validate(
|
|
178
|
+
valid,
|
|
179
|
+
message,
|
|
180
|
+
keyword: nil,
|
|
181
|
+
results: []
|
|
182
|
+
)
|
|
183
|
+
if !valid
|
|
184
|
+
throw(:jsi_validation_result, INVALID)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def schema_issue(*_)
|
|
189
|
+
# noop
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def initialize(valid)
|
|
194
|
+
@valid = valid
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def valid?
|
|
198
|
+
@valid
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# @private
|
|
202
|
+
def jsi_fingerprint
|
|
203
|
+
{
|
|
204
|
+
class: self.class,
|
|
205
|
+
valid: valid?,
|
|
206
|
+
}
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
module Validation
|
|
5
|
+
autoload :Error, 'jsi/validation/error'
|
|
6
|
+
|
|
7
|
+
autoload :Result, 'jsi/validation/result'
|
|
8
|
+
autoload :FullResult, 'jsi/validation/result'
|
|
9
|
+
autoload :ValidityResult, 'jsi/validation/result'
|
|
10
|
+
|
|
11
|
+
VALID = ValidityResult.new(true).freeze
|
|
12
|
+
|
|
13
|
+
INVALID = ValidityResult.new(false).freeze
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/jsi/version.rb
CHANGED
data/lib/jsi.rb
CHANGED
|
@@ -1,33 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "jsi/version"
|
|
2
4
|
require "pp"
|
|
3
5
|
require "set"
|
|
4
|
-
require "
|
|
6
|
+
require "json"
|
|
7
|
+
require "pathname"
|
|
8
|
+
require "bigdecimal"
|
|
9
|
+
require "addressable/uri"
|
|
10
|
+
|
|
5
11
|
require "jsi/util"
|
|
12
|
+
require "jsi/typelike_modules"
|
|
6
13
|
|
|
7
14
|
module JSI
|
|
8
15
|
# generally put in code paths that are not expected to be valid control flow paths.
|
|
9
16
|
# rather a NotImplementedCorrectlyError. but that's too long.
|
|
17
|
+
#
|
|
18
|
+
# if you've found this class because JSI has raised this error, please open an issue with the backtrace
|
|
19
|
+
# and any context you can provide at https://github.com/notEthan/jsi/issues
|
|
10
20
|
class Bug < NotImplementedError
|
|
11
21
|
end
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
# @private
|
|
24
|
+
ROOT_PATH = Pathname.new(__FILE__).dirname.parent.expand_path
|
|
25
|
+
|
|
26
|
+
# @private
|
|
27
|
+
RESOURCES_PATH = ROOT_PATH.join('{resources}')
|
|
28
|
+
|
|
29
|
+
# @private
|
|
30
|
+
SCHEMAS_PATH = RESOURCES_PATH.join('schemas')
|
|
31
|
+
|
|
32
|
+
autoload :Ptr, 'jsi/ptr'
|
|
33
|
+
|
|
34
|
+
# @private
|
|
35
|
+
# @deprecated
|
|
36
|
+
module JSON
|
|
37
|
+
Pointer = Ptr
|
|
38
|
+
end
|
|
39
|
+
|
|
14
40
|
autoload :PathedNode, 'jsi/pathed_node'
|
|
15
41
|
autoload :Typelike, 'jsi/typelike_modules'
|
|
16
42
|
autoload :Hashlike, 'jsi/typelike_modules'
|
|
17
43
|
autoload :Arraylike, 'jsi/typelike_modules'
|
|
18
44
|
autoload :Schema, 'jsi/schema'
|
|
45
|
+
autoload :SchemaSet, 'jsi/schema_set'
|
|
19
46
|
autoload :Base, 'jsi/base'
|
|
20
|
-
autoload :
|
|
21
|
-
autoload :
|
|
47
|
+
autoload :Metaschema, 'jsi/metaschema'
|
|
48
|
+
autoload :MetaschemaNode, 'jsi/metaschema_node'
|
|
22
49
|
autoload :SchemaClasses, 'jsi/schema_classes'
|
|
50
|
+
autoload :SchemaRegistry, 'jsi/schema_registry'
|
|
51
|
+
autoload :Validation, 'jsi/validation'
|
|
23
52
|
autoload :JSICoder, 'jsi/jsi_coder'
|
|
24
53
|
|
|
54
|
+
autoload :JSONSchemaOrgDraft04, 'schemas/json-schema.org/draft-04/schema'
|
|
55
|
+
autoload :JSONSchemaOrgDraft06, 'schemas/json-schema.org/draft-06/schema'
|
|
56
|
+
autoload :JSONSchemaOrgDraft07, 'schemas/json-schema.org/draft-07/schema'
|
|
57
|
+
|
|
25
58
|
autoload :SimpleWrap, 'jsi/simple_wrap'
|
|
26
59
|
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
60
|
+
# instantiates a given schema object as a JSI Schema.
|
|
61
|
+
#
|
|
62
|
+
# see {JSI::Schema.new_schema}
|
|
63
|
+
#
|
|
64
|
+
# @param (see JSI::Schema.new_schema)
|
|
65
|
+
# @return (see JSI::Schema.new_schema)
|
|
66
|
+
def self.new_schema(schema_object, **kw)
|
|
67
|
+
JSI::Schema.new_schema(schema_object, **kw)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# instantiates a given schema object as a JSI Schema and returns its JSI Schema Module.
|
|
71
|
+
#
|
|
72
|
+
# shortcut to chain {JSI::Schema.new_schema} + {Schema#jsi_schema_module}.
|
|
73
|
+
#
|
|
74
|
+
# @param (see JSI::Schema.new_schema)
|
|
75
|
+
# @return [Module, JSI::SchemaModule] the JSI Schema Module of the schema
|
|
76
|
+
def self.new_schema_module(schema_object, **kw)
|
|
77
|
+
JSI::Schema.new_schema(schema_object, **kw).jsi_schema_module
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @private @deprecated
|
|
81
|
+
def self.class_for_schemas(schemas)
|
|
82
|
+
SchemaClasses.class_for_schemas(schemas.map { |schema| JSI.new_schema(schema) })
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# `JSI.schema_registry` is the {JSI::SchemaRegistry} in which schemas are registered.
|
|
86
|
+
#
|
|
87
|
+
# @return [JSI::SchemaRegistry]
|
|
88
|
+
def self.schema_registry
|
|
89
|
+
return @schema_registry if instance_variable_defined?(:@schema_registry)
|
|
90
|
+
@schema_registry = SchemaRegistry.new
|
|
32
91
|
end
|
|
33
92
|
end
|
|
93
|
+
|
|
94
|
+
JSI.schema_registry.autoload_uri("http://json-schema.org/draft-04/schema") { JSI::JSONSchemaOrgDraft04.schema }
|
|
95
|
+
JSI.schema_registry.autoload_uri("http://json-schema.org/draft-06/schema") { JSI::JSONSchemaOrgDraft06.schema }
|
|
96
|
+
JSI.schema_registry.autoload_uri("http://json-schema.org/draft-07/schema") { JSI::JSONSchemaOrgDraft07.schema }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
metaschema_document = ::JSON.parse(SCHEMAS_PATH.join('json-schema.org/draft-04/schema.json').read)
|
|
5
|
+
JSONSchemaOrgDraft04 = MetaschemaNode.new(metaschema_document,
|
|
6
|
+
metaschema_instance_modules: [JSI::Schema::Draft04],
|
|
7
|
+
).jsi_schema_module
|
|
8
|
+
|
|
9
|
+
# the JSI schema module for `http://json-schema.org/draft-04/schema`
|
|
10
|
+
module JSONSchemaOrgDraft04
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
metaschema_document = ::JSON.parse(SCHEMAS_PATH.join('json-schema.org/draft-06/schema.json').read)
|
|
5
|
+
JSONSchemaOrgDraft06 = MetaschemaNode.new(metaschema_document,
|
|
6
|
+
metaschema_instance_modules: [JSI::Schema::Draft06],
|
|
7
|
+
).jsi_schema_module
|
|
8
|
+
|
|
9
|
+
# the JSI schema module for `http://json-schema.org/draft-06/schema`
|
|
10
|
+
module JSONSchemaOrgDraft06
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
metaschema_document = ::JSON.parse(SCHEMAS_PATH.join('json-schema.org/draft-07/schema.json').read)
|
|
5
|
+
JSONSchemaOrgDraft07 = MetaschemaNode.new(metaschema_document,
|
|
6
|
+
metaschema_instance_modules: [JSI::Schema::Draft07],
|
|
7
|
+
).jsi_schema_module
|
|
8
|
+
|
|
9
|
+
# the JSI schema module for `http://json-schema.org/draft-07/schema`
|
|
10
|
+
module JSONSchemaOrgDraft07
|
|
11
|
+
end
|
|
12
|
+
end
|
data/readme.rb
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# a small script following the code samples in the README
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
7
|
+
require 'jsi'
|
|
8
|
+
|
|
9
|
+
puts "creating a schema and assigning its schema module to a constant"
|
|
10
|
+
puts
|
|
11
|
+
|
|
12
|
+
contact_schema = JSI.new_schema({
|
|
13
|
+
"$schema" => "http://json-schema.org/draft-07/schema",
|
|
14
|
+
"description" => "A Contact",
|
|
15
|
+
"type" => "object",
|
|
16
|
+
"properties" => {
|
|
17
|
+
"name" => {
|
|
18
|
+
"type" => "string",
|
|
19
|
+
},
|
|
20
|
+
"phone" => {
|
|
21
|
+
"type" => "array",
|
|
22
|
+
"items" => {
|
|
23
|
+
"type" => "object",
|
|
24
|
+
"properties" => {
|
|
25
|
+
"location" => {
|
|
26
|
+
"type" => "string",
|
|
27
|
+
},
|
|
28
|
+
"number" => {
|
|
29
|
+
"type" => "string",
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
print 'contact_schema: '
|
|
38
|
+
pp contact_schema
|
|
39
|
+
|
|
40
|
+
print 'contact_schema.jsi_schema_module: '
|
|
41
|
+
pp contact_schema.jsi_schema_module
|
|
42
|
+
|
|
43
|
+
puts "constant assignment: Contact = contact_schema.jsi_schema_module"
|
|
44
|
+
Contact = contact_schema.jsi_schema_module
|
|
45
|
+
|
|
46
|
+
print 'contact_schema.jsi_schema_module: '
|
|
47
|
+
pp contact_schema.jsi_schema_module
|
|
48
|
+
|
|
49
|
+
puts
|
|
50
|
+
puts "creating and using an instance described by the schema"
|
|
51
|
+
puts
|
|
52
|
+
|
|
53
|
+
bill = Contact.new_jsi({
|
|
54
|
+
"name" => "bill",
|
|
55
|
+
"phone" => [
|
|
56
|
+
{
|
|
57
|
+
"location" => "home",
|
|
58
|
+
"number" => "555",
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"nickname" => "big b",
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
print 'bill: '
|
|
65
|
+
pp bill
|
|
66
|
+
|
|
67
|
+
print 'bill.name: '
|
|
68
|
+
pp bill.name
|
|
69
|
+
|
|
70
|
+
print 'bill.phone.map(&:location): '
|
|
71
|
+
pp bill.phone.map(&:location)
|
|
72
|
+
|
|
73
|
+
print 'bill.jsi_valid?: '
|
|
74
|
+
pp bill.jsi_valid?
|
|
75
|
+
|
|
76
|
+
bad = Contact.new_jsi({'phone' => [{'number' => [5, 5, 5]}]})
|
|
77
|
+
|
|
78
|
+
print 'bad: '
|
|
79
|
+
pp bad
|
|
80
|
+
|
|
81
|
+
print 'bad.phone.jsi_validate: '
|
|
82
|
+
pp bad.phone.jsi_validate
|
|
83
|
+
|
|
84
|
+
print 'bill.transform_values(&:size): '
|
|
85
|
+
pp bill.transform_values(&:size)
|
|
86
|
+
|
|
87
|
+
print "bill['nickname']: "
|
|
88
|
+
pp bill['nickname']
|
|
89
|
+
|
|
90
|
+
puts
|
|
91
|
+
puts "OOP: application-defined methods on schema modules apply to their instances"
|
|
92
|
+
puts
|
|
93
|
+
|
|
94
|
+
module Contact
|
|
95
|
+
def phone_numbers
|
|
96
|
+
phone.map(&:number)
|
|
97
|
+
end
|
|
98
|
+
def name
|
|
99
|
+
super + ' esq.'
|
|
100
|
+
end
|
|
101
|
+
def name=(name)
|
|
102
|
+
super(name.chomp(' esq.'))
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
print 'bill.name: '
|
|
107
|
+
pp bill.name
|
|
108
|
+
|
|
109
|
+
puts "bill.name = 'rob esq.'"
|
|
110
|
+
bill.name = 'rob esq.'
|
|
111
|
+
|
|
112
|
+
print "bill['name']: "
|
|
113
|
+
pp bill['name']
|
|
114
|
+
|
|
115
|
+
print 'bill.phone_numbers: '
|
|
116
|
+
pp bill.phone_numbers
|
|
117
|
+
|
|
118
|
+
puts
|
|
119
|
+
puts "OOP on subschemas"
|
|
120
|
+
puts
|
|
121
|
+
|
|
122
|
+
print "Contact.properties['phone'].items: "
|
|
123
|
+
pp Contact.properties['phone'].items
|
|
124
|
+
|
|
125
|
+
module Contact
|
|
126
|
+
Phone = properties['phone'].items
|
|
127
|
+
module Phone
|
|
128
|
+
def number_with_dashes
|
|
129
|
+
number.split(//).join('-')
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
print "Contact.properties['phone'].items: "
|
|
135
|
+
pp Contact.properties['phone'].items
|
|
136
|
+
|
|
137
|
+
print 'bill.phone.first.number_with_dashes: '
|
|
138
|
+
pp bill.phone.first.number_with_dashes
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "http://json-schema.org/draft-04/schema#",
|
|
3
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
4
|
+
"description": "Core schema meta-schema",
|
|
5
|
+
"definitions": {
|
|
6
|
+
"schemaArray": {
|
|
7
|
+
"type": "array",
|
|
8
|
+
"minItems": 1,
|
|
9
|
+
"items": { "$ref": "#" }
|
|
10
|
+
},
|
|
11
|
+
"positiveInteger": {
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"minimum": 0
|
|
14
|
+
},
|
|
15
|
+
"positiveIntegerDefault0": {
|
|
16
|
+
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
|
|
17
|
+
},
|
|
18
|
+
"simpleTypes": {
|
|
19
|
+
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
|
|
20
|
+
},
|
|
21
|
+
"stringArray": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": { "type": "string" },
|
|
24
|
+
"minItems": 1,
|
|
25
|
+
"uniqueItems": true
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"type": "object",
|
|
29
|
+
"properties": {
|
|
30
|
+
"id": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
},
|
|
33
|
+
"$schema": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"title": {
|
|
37
|
+
"type": "string"
|
|
38
|
+
},
|
|
39
|
+
"description": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
},
|
|
42
|
+
"default": {},
|
|
43
|
+
"multipleOf": {
|
|
44
|
+
"type": "number",
|
|
45
|
+
"minimum": 0,
|
|
46
|
+
"exclusiveMinimum": true
|
|
47
|
+
},
|
|
48
|
+
"maximum": {
|
|
49
|
+
"type": "number"
|
|
50
|
+
},
|
|
51
|
+
"exclusiveMaximum": {
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"default": false
|
|
54
|
+
},
|
|
55
|
+
"minimum": {
|
|
56
|
+
"type": "number"
|
|
57
|
+
},
|
|
58
|
+
"exclusiveMinimum": {
|
|
59
|
+
"type": "boolean",
|
|
60
|
+
"default": false
|
|
61
|
+
},
|
|
62
|
+
"maxLength": { "$ref": "#/definitions/positiveInteger" },
|
|
63
|
+
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
|
64
|
+
"pattern": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"format": "regex"
|
|
67
|
+
},
|
|
68
|
+
"additionalItems": {
|
|
69
|
+
"anyOf": [
|
|
70
|
+
{ "type": "boolean" },
|
|
71
|
+
{ "$ref": "#" }
|
|
72
|
+
],
|
|
73
|
+
"default": {}
|
|
74
|
+
},
|
|
75
|
+
"items": {
|
|
76
|
+
"anyOf": [
|
|
77
|
+
{ "$ref": "#" },
|
|
78
|
+
{ "$ref": "#/definitions/schemaArray" }
|
|
79
|
+
],
|
|
80
|
+
"default": {}
|
|
81
|
+
},
|
|
82
|
+
"maxItems": { "$ref": "#/definitions/positiveInteger" },
|
|
83
|
+
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
|
84
|
+
"uniqueItems": {
|
|
85
|
+
"type": "boolean",
|
|
86
|
+
"default": false
|
|
87
|
+
},
|
|
88
|
+
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
|
|
89
|
+
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
|
90
|
+
"required": { "$ref": "#/definitions/stringArray" },
|
|
91
|
+
"additionalProperties": {
|
|
92
|
+
"anyOf": [
|
|
93
|
+
{ "type": "boolean" },
|
|
94
|
+
{ "$ref": "#" }
|
|
95
|
+
],
|
|
96
|
+
"default": {}
|
|
97
|
+
},
|
|
98
|
+
"definitions": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"additionalProperties": { "$ref": "#" },
|
|
101
|
+
"default": {}
|
|
102
|
+
},
|
|
103
|
+
"properties": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"additionalProperties": { "$ref": "#" },
|
|
106
|
+
"default": {}
|
|
107
|
+
},
|
|
108
|
+
"patternProperties": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"additionalProperties": { "$ref": "#" },
|
|
111
|
+
"default": {}
|
|
112
|
+
},
|
|
113
|
+
"dependencies": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"additionalProperties": {
|
|
116
|
+
"anyOf": [
|
|
117
|
+
{ "$ref": "#" },
|
|
118
|
+
{ "$ref": "#/definitions/stringArray" }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"enum": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"minItems": 1,
|
|
125
|
+
"uniqueItems": true
|
|
126
|
+
},
|
|
127
|
+
"type": {
|
|
128
|
+
"anyOf": [
|
|
129
|
+
{ "$ref": "#/definitions/simpleTypes" },
|
|
130
|
+
{
|
|
131
|
+
"type": "array",
|
|
132
|
+
"items": { "$ref": "#/definitions/simpleTypes" },
|
|
133
|
+
"minItems": 1,
|
|
134
|
+
"uniqueItems": true
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
"format": { "type": "string" },
|
|
139
|
+
"allOf": { "$ref": "#/definitions/schemaArray" },
|
|
140
|
+
"anyOf": { "$ref": "#/definitions/schemaArray" },
|
|
141
|
+
"oneOf": { "$ref": "#/definitions/schemaArray" },
|
|
142
|
+
"not": { "$ref": "#" }
|
|
143
|
+
},
|
|
144
|
+
"dependencies": {
|
|
145
|
+
"exclusiveMaximum": [ "maximum" ],
|
|
146
|
+
"exclusiveMinimum": [ "minimum" ]
|
|
147
|
+
},
|
|
148
|
+
"default": {}
|
|
149
|
+
}
|