jsi 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/jsi/base.rb +39 -26
- data/lib/jsi/schema.rb +27 -0
- data/lib/jsi/util.rb +1 -0
- data/lib/jsi/version.rb +1 -1
- data/test/base_array_test.rb +55 -0
- data/test/base_hash_test.rb +59 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12a262c5b9ec6c22d16c8e4f5cb983c92266d165964a120ffcd72f7e0bd877d1
|
4
|
+
data.tar.gz: 3e4671dda156d3d8073e9f7af42e3335af8f3482719a0495d4f57a2dfaaf12c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f9c9816756bb70c16498d2ba503c7b0148533b37ae065d8426e654a0644066db6108a6a7d79789bb039f4911432b4273ca85d6a08a47783d0e992af06e248c2
|
7
|
+
data.tar.gz: c9859fffe7cffbdde822530c828db5344cefa12e2b94eef5d3732d88dca741db5e93414c2800d681fba4555b6694d5bf873cdee08ccbfbce293f3e159ac2749e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# v0.0.3
|
2
|
+
|
3
|
+
- JSI::Base returns an instance of the default value for the schema if applicable
|
4
|
+
- JSI::Base instance method #class_for_schema may be overridden by subclasses
|
5
|
+
- bugfixes and internal refactoring
|
6
|
+
|
1
7
|
# v0.0.2
|
2
8
|
|
3
9
|
- JSI::JSON::Node and other utilities duck-type better with #to_hash and #to_ary
|
data/lib/jsi/base.rb
CHANGED
@@ -67,14 +67,14 @@ module JSI
|
|
67
67
|
# a Node already).
|
68
68
|
#
|
69
69
|
# @param instance [Object] the JSON Schema instance being represented
|
70
|
-
# @param
|
71
|
-
# from which this JSI originated
|
72
|
-
def initialize(instance,
|
70
|
+
# @param ancestor [JSI::Base] for internal use, specifies an ancestor
|
71
|
+
# from which this JSI originated to calculate #parents
|
72
|
+
def initialize(instance, ancestor: nil)
|
73
73
|
unless respond_to?(:schema)
|
74
74
|
raise(TypeError, "cannot instantiate #{self.class.inspect} which has no method #schema. please use JSI.class_for_schema")
|
75
75
|
end
|
76
76
|
|
77
|
-
@
|
77
|
+
@ancestor = ancestor || self
|
78
78
|
self.instance = instance
|
79
79
|
|
80
80
|
if @instance.is_a?(JSI::JSON::HashNode)
|
@@ -87,6 +87,9 @@ module JSI
|
|
87
87
|
# the instance of the json-schema. this is a JSI::JSON::Node.
|
88
88
|
attr_reader :instance
|
89
89
|
|
90
|
+
# a JSI which is an ancestor of this
|
91
|
+
attr_reader :ancestor
|
92
|
+
|
90
93
|
# each is overridden by BaseHash or BaseArray when appropriate. the base
|
91
94
|
# #each is not actually implemented, along with all the methods of Enumerable.
|
92
95
|
def each
|
@@ -99,8 +102,8 @@ module JSI
|
|
99
102
|
#
|
100
103
|
# @return [Array<JSI::Base>]
|
101
104
|
def parents
|
102
|
-
parent = @
|
103
|
-
(@
|
105
|
+
parent = @ancestor
|
106
|
+
(@ancestor.instance.path.size...self.instance.path.size).map do |i|
|
104
107
|
parent.tap do
|
105
108
|
parent = parent[self.instance.path[i]]
|
106
109
|
end
|
@@ -123,7 +126,7 @@ module JSI
|
|
123
126
|
if derefed.object_id == instance.object_id
|
124
127
|
self
|
125
128
|
else
|
126
|
-
self.class.new(derefed,
|
129
|
+
self.class.new(derefed, ancestor: @ancestor)
|
127
130
|
end
|
128
131
|
end
|
129
132
|
|
@@ -136,7 +139,7 @@ module JSI
|
|
136
139
|
# @return [JSI::Base subclass the same as self] the modified copy of self
|
137
140
|
def modified_copy(&block)
|
138
141
|
modified_instance = instance.modified_copy(&block)
|
139
|
-
self.class.new(modified_instance,
|
142
|
+
self.class.new(modified_instance, ancestor: @ancestor)
|
140
143
|
end
|
141
144
|
|
142
145
|
def fragment
|
@@ -228,6 +231,12 @@ module JSI
|
|
228
231
|
instance[subscript] = value
|
229
232
|
end
|
230
233
|
end
|
234
|
+
|
235
|
+
# this is an instance method in order to allow subclasses of JSI classes to
|
236
|
+
# override it to point to other subclasses corresponding to other schemas.
|
237
|
+
def class_for_schema(schema)
|
238
|
+
JSI.class_for_schema(schema)
|
239
|
+
end
|
231
240
|
end
|
232
241
|
|
233
242
|
# this module is just a namespace for schema classes.
|
@@ -247,13 +256,7 @@ module JSI
|
|
247
256
|
|
248
257
|
# see {JSI.class_for_schema}
|
249
258
|
def SchemaClasses.class_for_schema(schema_object)
|
250
|
-
|
251
|
-
schema__ = schema_object
|
252
|
-
else
|
253
|
-
schema__ = JSI::Schema.new(schema_object)
|
254
|
-
end
|
255
|
-
|
256
|
-
memoize(:class_for_schema, schema__) do |schema_|
|
259
|
+
memoize(:class_for_schema, JSI::Schema.from_object(schema_object)) do |schema_|
|
257
260
|
begin
|
258
261
|
begin
|
259
262
|
Class.new(Base).instance_exec(schema_) do |schema|
|
@@ -284,13 +287,7 @@ module JSI
|
|
284
287
|
# class will be defined. users should use #[] and #[]= to access properties
|
285
288
|
# whose names conflict with existing methods.
|
286
289
|
def SchemaClasses.module_for_schema(schema_object)
|
287
|
-
|
288
|
-
schema__ = schema_object
|
289
|
-
else
|
290
|
-
schema__ = JSI::Schema.new(schema_object)
|
291
|
-
end
|
292
|
-
|
293
|
-
memoize(:module_for_schema, schema__) do |schema_|
|
290
|
+
memoize(:module_for_schema, JSI::Schema.from_object(schema_object)) do |schema_|
|
294
291
|
Module.new.tap do |m|
|
295
292
|
m.instance_exec(schema_) do |schema|
|
296
293
|
define_method(:schema) { schema }
|
@@ -369,8 +366,16 @@ module JSI
|
|
369
366
|
property_schema = schema.subschema_for_property(property_name)
|
370
367
|
property_schema = property_schema && property_schema.match_to_instance(instance[property_name])
|
371
368
|
|
372
|
-
if property_schema &&
|
373
|
-
|
369
|
+
if !instance.key?(property_name) && property_schema && property_schema.schema_object.key?('default')
|
370
|
+
# use the default value
|
371
|
+
default = property_schema.schema_object['default']
|
372
|
+
if default.respond_to?(:to_hash) || default.respond_to?(:to_ary)
|
373
|
+
class_for_schema(property_schema).new(default, ancestor: @ancestor)
|
374
|
+
else
|
375
|
+
default
|
376
|
+
end
|
377
|
+
elsif property_schema && (instance[property_name].respond_to?(:to_hash) || instance[property_name].respond_to?(:to_ary))
|
378
|
+
class_for_schema(property_schema).new(instance[property_name], ancestor: @ancestor)
|
374
379
|
else
|
375
380
|
instance[property_name]
|
376
381
|
end
|
@@ -426,8 +431,16 @@ module JSI
|
|
426
431
|
index_schema = schema.subschema_for_index(i)
|
427
432
|
index_schema = index_schema && index_schema.match_to_instance(instance[i])
|
428
433
|
|
429
|
-
if index_schema &&
|
430
|
-
|
434
|
+
if !instance.each_index.to_a.include?(i) && index_schema && index_schema.schema_object.key?('default')
|
435
|
+
# use the default value
|
436
|
+
default = index_schema.schema_object['default']
|
437
|
+
if default.respond_to?(:to_hash) || default.respond_to?(:to_ary)
|
438
|
+
class_for_schema(index_schema).new(default, ancestor: @ancestor)
|
439
|
+
else
|
440
|
+
default
|
441
|
+
end
|
442
|
+
elsif index_schema && (instance[i].respond_to?(:to_hash) || instance[i].respond_to?(:to_ary))
|
443
|
+
class_for_schema(index_schema).new(instance[i], ancestor: @ancestor)
|
431
444
|
else
|
432
445
|
instance[i]
|
433
446
|
end
|
data/lib/jsi/schema.rb
CHANGED
@@ -7,6 +7,16 @@ module JSI
|
|
7
7
|
class Schema
|
8
8
|
include Memoize
|
9
9
|
|
10
|
+
class << self
|
11
|
+
def from_object(schema_object)
|
12
|
+
if schema_object.is_a?(Schema)
|
13
|
+
schema_object
|
14
|
+
else
|
15
|
+
new(schema_object)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
10
20
|
# initializes a schema from a given JSI::Base, JSI::JSON::Node, or hash.
|
11
21
|
# @param schema_object [JSI::Base, #to_hash] the schema
|
12
22
|
def initialize(schema_object)
|
@@ -118,6 +128,7 @@ module JSI
|
|
118
128
|
# matching allOf is questionable. all of the schemas must be matched but we just return the first match.
|
119
129
|
# there isn't really a better answer with the current implementation. merging the schemas together
|
120
130
|
# is a thought but is not practical.
|
131
|
+
instance = instance.deref if instance.is_a?(JSI::JSON::Node)
|
121
132
|
%w(oneOf allOf anyOf).select { |k| schema_node[k].respond_to?(:to_ary) }.each do |someof_key|
|
122
133
|
schema_node[someof_key].map(&:deref).map do |someof_node|
|
123
134
|
someof_schema = self.class.new(someof_node)
|
@@ -201,6 +212,22 @@ module JSI
|
|
201
212
|
end
|
202
213
|
end
|
203
214
|
|
215
|
+
def default_value
|
216
|
+
if schema_node.key?('default')
|
217
|
+
if schema_node['default'].respond_to?(:to_ary) || schema_node['default'].respond_to?(:to_hash)
|
218
|
+
schema_class.new(schema_node['default'])
|
219
|
+
else
|
220
|
+
schema_node['default']
|
221
|
+
end
|
222
|
+
else
|
223
|
+
nil
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def default_value?
|
228
|
+
schema_node.key?('default')
|
229
|
+
end
|
230
|
+
|
204
231
|
# @return [Array<String>] array of schema validation error messages for
|
205
232
|
# the given instance against this schema
|
206
233
|
def fully_validate(instance)
|
data/lib/jsi/util.rb
CHANGED
data/lib/jsi/version.rb
CHANGED
data/test/base_array_test.rb
CHANGED
@@ -20,6 +20,61 @@ describe JSI::BaseArray do
|
|
20
20
|
let(:class_for_schema) { JSI.class_for_schema(schema) }
|
21
21
|
let(:subject) { class_for_schema.new(instance) }
|
22
22
|
|
23
|
+
describe '#[] with a default that is a basic type' do
|
24
|
+
let(:schema_content) do
|
25
|
+
{
|
26
|
+
'type' => 'array',
|
27
|
+
'items' => {'default' => 'foo'},
|
28
|
+
}
|
29
|
+
end
|
30
|
+
describe 'default value' do
|
31
|
+
let(:document) { [1] }
|
32
|
+
it 'returns the default value' do
|
33
|
+
assert_equal('foo', subject[2])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
describe 'nondefault value (basic type)' do
|
37
|
+
let(:document) { ['who'] }
|
38
|
+
it 'returns the nondefault value' do
|
39
|
+
assert_equal('who', subject[0])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
describe 'nondefault value (nonbasic type)' do
|
43
|
+
let(:document) { [[2]] }
|
44
|
+
it 'returns the nondefault value' do
|
45
|
+
assert_instance_of(JSI.class_for_schema(schema['items']), subject[0])
|
46
|
+
assert_equal([2], subject[0].as_json)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
describe '#[] with a default that is a nonbasic type' do
|
51
|
+
let(:schema_content) do
|
52
|
+
{
|
53
|
+
'type' => 'array',
|
54
|
+
'items' => {'default' => {'foo' => 2}},
|
55
|
+
}
|
56
|
+
end
|
57
|
+
describe 'default value' do
|
58
|
+
let(:document) { [{'bar' => 3}] }
|
59
|
+
it 'returns the default value' do
|
60
|
+
assert_instance_of(JSI.class_for_schema(schema['items']), subject[1])
|
61
|
+
assert_equal({'foo' => 2}, subject[1].as_json)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe 'nondefault value (basic type)' do
|
65
|
+
let(:document) { [true, 'who'] }
|
66
|
+
it 'returns the nondefault value' do
|
67
|
+
assert_equal('who', subject[1])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
describe 'nondefault value (nonbasic type)' do
|
71
|
+
let(:document) { [true, [2]] }
|
72
|
+
it 'returns the nondefault value' do
|
73
|
+
assert_instance_of(JSI.class_for_schema(schema['items']), subject[1])
|
74
|
+
assert_equal([2], subject[1].as_json)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
23
78
|
describe 'arraylike []=' do
|
24
79
|
it 'sets an index' do
|
25
80
|
orig_2 = subject[2]
|
data/test/base_hash_test.rb
CHANGED
@@ -19,6 +19,65 @@ describe JSI::BaseHash do
|
|
19
19
|
let(:class_for_schema) { JSI.class_for_schema(schema) }
|
20
20
|
let(:subject) { class_for_schema.new(instance) }
|
21
21
|
|
22
|
+
describe '#[] with a default that is a basic type' do
|
23
|
+
let(:schema_content) do
|
24
|
+
{
|
25
|
+
'type' => 'object',
|
26
|
+
'properties' => {
|
27
|
+
'foo' => {'default' => 'foo'},
|
28
|
+
},
|
29
|
+
}
|
30
|
+
end
|
31
|
+
describe 'default value' do
|
32
|
+
let(:document) { {'bar' => 3} }
|
33
|
+
it 'returns the default value' do
|
34
|
+
assert_equal('foo', subject.foo)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
describe 'nondefault value (basic type)' do
|
38
|
+
let(:document) { {'foo' => 'who'} }
|
39
|
+
it 'returns the nondefault value' do
|
40
|
+
assert_equal('who', subject.foo)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
describe 'nondefault value (nonbasic type)' do
|
44
|
+
let(:document) { {'foo' => [2]} }
|
45
|
+
it 'returns the nondefault value' do
|
46
|
+
assert_instance_of(JSI.class_for_schema(schema['properties']['foo']), subject.foo)
|
47
|
+
assert_equal([2], subject.foo.as_json)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
describe '#[] with a default that is a nonbasic type' do
|
52
|
+
let(:schema_content) do
|
53
|
+
{
|
54
|
+
'type' => 'object',
|
55
|
+
'properties' => {
|
56
|
+
'foo' => {'default' => {'foo' => 2}},
|
57
|
+
},
|
58
|
+
}
|
59
|
+
end
|
60
|
+
describe 'default value' do
|
61
|
+
let(:document) { {'bar' => 3} }
|
62
|
+
it 'returns the default value' do
|
63
|
+
assert_instance_of(JSI.class_for_schema(schema['properties']['foo']), subject.foo)
|
64
|
+
assert_equal({'foo' => 2}, subject.foo.as_json)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
describe 'nondefault value (basic type)' do
|
68
|
+
let(:document) { {'foo' => 'who'} }
|
69
|
+
it 'returns the nondefault value' do
|
70
|
+
assert_equal('who', subject.foo)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
describe 'nondefault value (nonbasic type)' do
|
74
|
+
let(:document) { {'foo' => [2]} }
|
75
|
+
it 'returns the nondefault value' do
|
76
|
+
assert_instance_of(JSI.class_for_schema(schema['properties']['foo']), subject.foo)
|
77
|
+
assert_equal([2], subject.foo.as_json)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
22
81
|
describe 'hashlike []=' do
|
23
82
|
it 'sets a property' do
|
24
83
|
orig_foo = subject['foo']
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ethan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json-schema
|