jsi 0.0.2 → 0.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61dd1e2dc8c145ccf5acdcd6a0d6eaeef0d61dd85e876347af89f7168e838319
4
- data.tar.gz: de6f01e5e859f2b3039b7d2c6f734b1e30b97b8c946f2444783581931d5939e9
3
+ metadata.gz: 12a262c5b9ec6c22d16c8e4f5cb983c92266d165964a120ffcd72f7e0bd877d1
4
+ data.tar.gz: 3e4671dda156d3d8073e9f7af42e3335af8f3482719a0495d4f57a2dfaaf12c9
5
5
  SHA512:
6
- metadata.gz: c15c232306814b19a3b84f94c9bd5bacfa261c7124e007ad8961e6e7a28495c23e675963aca024d2abb29613ba9092313cf11b0344feb3e20f38dec6dcf511b1
7
- data.tar.gz: c00160e62da570c862b694d516bb157019b1799dcff24f594f494fa695c45fcfaa4a5e34e93b8bf35978c28e9bf13e84ed86b3938eff3b7443c6e4cae81118af
6
+ metadata.gz: 7f9c9816756bb70c16498d2ba503c7b0148533b37ae065d8426e654a0644066db6108a6a7d79789bb039f4911432b4273ca85d6a08a47783d0e992af06e248c2
7
+ data.tar.gz: c9859fffe7cffbdde822530c828db5344cefa12e2b94eef5d3732d88dca741db5e93414c2800d681fba4555b6694d5bf873cdee08ccbfbce293f3e159ac2749e
@@ -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
@@ -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 origin [JSI::Base] for internal use, specifies a parent
71
- # from which this JSI originated
72
- def initialize(instance, origin: nil)
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
- @origin = origin || self
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 = @origin
103
- (@origin.instance.path.size...self.instance.path.size).map do |i|
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, origin: @origin)
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, origin: @origin)
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
- if schema_object.is_a?(JSI::Schema)
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
- if schema_object.is_a?(JSI::Schema)
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 && instance[property_name].is_a?(JSON::Node)
373
- JSI.class_for_schema(property_schema).new(instance[property_name], origin: @origin)
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 && instance[i].is_a?(JSON::Node)
430
- JSI.class_for_schema(index_schema).new(instance[i], origin: @origin)
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
@@ -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)
@@ -79,6 +79,7 @@ module JSI
79
79
  end
80
80
  module_function :ycomb
81
81
  end
82
+ public
82
83
  extend Util
83
84
 
84
85
  module FingerprintHash
@@ -1,3 +1,3 @@
1
1
  module JSI
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
@@ -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]
@@ -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.2
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: 2018-09-27 00:00:00.000000000 Z
11
+ date: 2019-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json-schema