jsi 0.1.0 → 0.2.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.
@@ -1,5 +1,8 @@
1
1
  module JSI
2
2
  module Util
3
+ # a proc which does nothing
4
+ NOOP = -> (*_) { }
5
+
3
6
  # returns a version of the given hash, in which any symbol keys are
4
7
  # converted to strings. behavior on collisions is undefined (but in the
5
8
  # future could take a block like
@@ -1,3 +1,3 @@
1
1
  module JSI
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -5,7 +5,8 @@ describe JSI::BaseArray do
5
5
  ['foo', {'lamp' => [3]}, ['q', 'r']]
6
6
  end
7
7
  let(:path) { [] }
8
- let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
8
+ let(:pointer) { JSI::JSON::Pointer.new(path) }
9
+ let(:instance) { JSI::JSON::Node.new_by_type(document, pointer) }
9
10
  let(:schema_content) do
10
11
  {
11
12
  'type' => 'array',
@@ -106,40 +107,40 @@ describe JSI::BaseArray do
106
107
  # these methods just delegate to Array so not going to test excessively
107
108
  describe 'index only methods' do
108
109
  it('#each_index') { assert_equal([0, 1, 2], subject.each_index.to_a) }
109
- it('#empty?') { assert_equal(false, subject.empty?) }
110
- it('#length') { assert_equal(3, subject.length) }
111
- it('#size') { assert_equal(3, subject.size) }
110
+ it('#empty?') { assert_equal(false, subject.empty?) }
111
+ it('#length') { assert_equal(3, subject.length) }
112
+ it('#size') { assert_equal(3, subject.size) }
112
113
  end
113
114
  describe 'index + element methods' do
114
- it('#|') { assert_equal(['foo', subject[1], subject[2], 0], subject | [0]) }
115
- it('#&') { assert_equal(['foo'], subject & ['foo']) }
116
- it('#*') { assert_equal(subject.to_a, subject * 1) }
117
- it('#+') { assert_equal(subject.to_a, subject + []) }
118
- it('#-') { assert_equal([subject[1], subject[2]], subject - ['foo']) }
119
- it('#<=>') { assert_equal(1, subject <=> []) }
120
- it('#<=>') { assert_equal(-1, [] <=> subject) }
115
+ it('#|') { assert_equal(['foo', subject[1], subject[2], 0], subject | [0]) }
116
+ it('#&') { assert_equal(['foo'], subject & ['foo']) }
117
+ it('#*') { assert_equal(subject.to_a, subject * 1) }
118
+ it('#+') { assert_equal(subject.to_a, subject + []) }
119
+ it('#-') { assert_equal([subject[1], subject[2]], subject - ['foo']) }
120
+ it('#<=>') { assert_equal(1, subject <=> []) }
121
+ it('#<=>') { assert_equal(-1, [] <=> subject) }
121
122
  require 'abbrev'
122
- it('#abbrev') { assert_equal({'a' => 'a'}, class_for_schema.new(['a']).abbrev) }
123
- it('#assoc') { assert_equal(['q', 'r'], subject.instance.assoc('q')) }
124
- it('#at') { assert_equal('foo', subject.at(0)) }
125
- it('#bsearch') { assert_equal(nil, subject.bsearch { false }) }
126
- it('#bsearch_index') { assert_equal(nil, subject.bsearch_index { false }) } if [].respond_to?(:bsearch_index)
127
- it('#combination') { assert_equal([['foo'], [subject[1]], [subject[2]]], subject.combination(1).to_a) }
128
- it('#count') { assert_equal(1, subject.count('foo')) }
129
- it('#cycle') { assert_equal(subject.to_a, subject.cycle(1).to_a) }
130
- it('#dig') { assert_equal(3, subject.dig(1, 'lamp', 0)) } if [].respond_to?(:dig)
131
- it('#drop') { assert_equal([subject[2]], subject.drop(2)) }
132
- it('#drop_while') { assert_equal([subject[1], subject[2]], subject.drop_while { |e| e == 'foo' }) }
133
- it('#fetch') { assert_equal('foo', subject.fetch(0)) }
134
- it('#find_index') { assert_equal(0, subject.find_index { true }) }
135
- it('#first') { assert_equal('foo', subject.first) }
136
- it('#include?') { assert_equal(true, subject.include?('foo')) }
137
- it('#index') { assert_equal(0, subject.index('foo')) }
138
- it('#join') { assert_equal('a b', class_for_schema.new(['a', 'b']).join(' ')) }
139
- it('#last') { assert_equal(subject[2], subject.last) }
140
- it('#pack') { assert_equal(' ', class_for_schema.new([32]).pack('c')) }
141
- it('#permutation') { assert_equal([['foo'], [subject[1]], [subject[2]]], subject.permutation(1).to_a) }
142
- it('#product') { assert_equal([], subject.product([])) }
123
+ it('#abbrev') { assert_equal({'a' => 'a'}, class_for_schema.new(['a']).abbrev) }
124
+ it('#assoc') { assert_equal(['q', 'r'], subject.assoc('q')) }
125
+ it('#at') { assert_equal('foo', subject.at(0)) }
126
+ it('#bsearch') { assert_equal(nil, subject.bsearch { false }) }
127
+ it('#bsearch_index') { assert_equal(nil, subject.bsearch_index { false }) } if [].respond_to?(:bsearch_index)
128
+ it('#combination') { assert_equal([['foo'], [subject[1]], [subject[2]]], subject.combination(1).to_a) }
129
+ it('#count') { assert_equal(1, subject.count('foo')) }
130
+ it('#cycle') { assert_equal(subject.to_a, subject.cycle(1).to_a) }
131
+ it('#dig') { assert_equal(3, subject.dig(1, 'lamp', 0)) } if [].respond_to?(:dig)
132
+ it('#drop') { assert_equal([subject[2]], subject.drop(2)) }
133
+ it('#drop_while') { assert_equal([subject[1], subject[2]], subject.drop_while { |e| e == 'foo' }) }
134
+ it('#fetch') { assert_equal('foo', subject.fetch(0)) }
135
+ it('#find_index') { assert_equal(0, subject.find_index { true }) }
136
+ it('#first') { assert_equal('foo', subject.first) }
137
+ it('#include?') { assert_equal(true, subject.include?('foo')) }
138
+ it('#index') { assert_equal(0, subject.index('foo')) }
139
+ it('#join') { assert_equal('a b', class_for_schema.new(['a', 'b']).join(' ')) }
140
+ it('#last') { assert_equal(subject[2], subject.last) }
141
+ it('#pack') { assert_equal(' ', class_for_schema.new([32]).pack('c')) }
142
+ it('#permutation') { assert_equal([['foo'], [subject[1]], [subject[2]]], subject.permutation(1).to_a) }
143
+ it('#product') { assert_equal([], subject.product([])) }
143
144
  # due to differences in implementation between #assoc and #rassoc, the reason for which
144
145
  # I cannot begin to fathom, assoc works but rassoc does not because rassoc has different
145
146
  # type checking than assoc for the array(like) array elements.
@@ -147,32 +148,43 @@ describe JSI::BaseArray do
147
148
  # assoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3780-L3813
148
149
  # rassoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3815-L3847
149
150
  # for this reason, rassoc is NOT defined on Arraylike and #content must be called.
150
- it('#rassoc') { assert_equal(['q', 'r'], subject.instance.content.rassoc('r')) }
151
+ it('#rassoc') { assert_equal(['q', 'r'], subject.instance.content.rassoc('r')) }
151
152
  it('#repeated_combination') { assert_equal([[]], subject.repeated_combination(0).to_a) }
152
153
  it('#repeated_permutation') { assert_equal([[]], subject.repeated_permutation(0).to_a) }
153
- it('#reverse') { assert_equal([subject[2], subject[1], 'foo'], subject.reverse) }
154
- it('#reverse_each') { assert_equal([subject[2], subject[1], 'foo'], subject.reverse_each.to_a) }
155
- it('#rindex') { assert_equal(0, subject.rindex('foo')) }
156
- it('#rotate') { assert_equal([subject[1], subject[2], 'foo'], subject.rotate) }
157
- it('#sample') { assert_equal('a', class_for_schema.new(['a']).sample) }
158
- it('#shelljoin') { assert_equal('a', class_for_schema.new(['a']).shelljoin) } if [].respond_to?(:shelljoin)
159
- it('#shuffle') { assert_equal(3, subject.shuffle.size) }
160
- it('#slice') { assert_equal(['foo'], subject.slice(0, 1)) }
161
- it('#sort') { assert_equal(['a'], class_for_schema.new(['a']).sort) }
162
- it('#take') { assert_equal(['foo'], subject.take(1)) }
163
- it('#take_while') { assert_equal([], subject.take_while { false }) }
164
- it('#transpose') { assert_equal([], class_for_schema.new([]).transpose) }
165
- it('#uniq') { assert_equal(subject.to_a, subject.uniq) }
166
- it('#values_at') { assert_equal(['foo'], subject.values_at(0)) }
167
- it('#zip') { assert_equal([['foo', 'foo'], [subject[1], subject[1]], [subject[2], subject[2]]], subject.zip(subject)) }
154
+ it('#reverse') { assert_equal([subject[2], subject[1], 'foo'], subject.reverse) }
155
+ it('#reverse_each') { assert_equal([subject[2], subject[1], 'foo'], subject.reverse_each.to_a) }
156
+ it('#rindex') { assert_equal(0, subject.rindex('foo')) }
157
+ it('#rotate') { assert_equal([subject[1], subject[2], 'foo'], subject.rotate) }
158
+ it('#sample') { assert_equal('a', class_for_schema.new(['a']).sample) }
159
+ it('#shelljoin') { assert_equal('a', class_for_schema.new(['a']).shelljoin) } if [].respond_to?(:shelljoin)
160
+ it('#shuffle') { assert_equal(3, subject.shuffle.size) }
161
+ it('#slice') { assert_equal(['foo'], subject.slice(0, 1)) }
162
+ it('#sort') { assert_equal(['a'], class_for_schema.new(['a']).sort) }
163
+ it('#take') { assert_equal(['foo'], subject.take(1)) }
164
+ it('#take_while') { assert_equal([], subject.take_while { false }) }
165
+ it('#transpose') { assert_equal([], class_for_schema.new([]).transpose) }
166
+ it('#uniq') { assert_equal(subject.to_a, subject.uniq) }
167
+ it('#values_at') { assert_equal(['foo'], subject.values_at(0)) }
168
+ it('#zip') { assert_equal([['foo', 'foo'], [subject[1], subject[1]], [subject[2], subject[2]]], subject.zip(subject)) }
169
+ end
170
+ describe 'with an instance that has to_ary but not other ary instance methods' do
171
+ let(:instance) { SortOfArray.new(['foo', {'lamp' => SortOfArray.new([3])}, SortOfArray.new(['q', 'r'])]) }
172
+ describe 'delegating instance methods to #to_ary' do
173
+ it('#each_index') { assert_equal([0, 1, 2], subject.each_index.to_a) }
174
+ it('#size') { assert_equal(3, subject.size) }
175
+ it('#count') { assert_equal(1, subject.count('foo')) }
176
+ it('#slice') { assert_equal(['foo'], subject.slice(0, 1)) }
177
+ it('#[]') { assert_equal(SortOfArray.new(['q', 'r']), subject[2].instance) }
178
+ it('#as_json') { assert_equal(['foo', {'lamp' => [3]}, ['q', 'r']], subject.as_json) }
179
+ end
168
180
  end
169
181
  describe 'modified copy methods' do
170
- it('#reject') { assert_equal(class_for_schema.new(JSI::JSON::ArrayNode.new(['foo'], [])), subject.reject { |e| e != 'foo' }) }
182
+ it('#reject') { assert_equal(class_for_schema.new(JSI::JSON::ArrayNode.new(['foo'], pointer)), subject.reject { |e| e != 'foo' }) }
171
183
  it('#reject block var') do
172
184
  subj_a = subject.to_a
173
185
  subject.reject { |e| assert_equal(e, subj_a.shift) }
174
186
  end
175
- it('#select') { assert_equal(class_for_schema.new(JSI::JSON::ArrayNode.new(['foo'], [])), subject.select { |e| e == 'foo' }) }
187
+ it('#select') { assert_equal(class_for_schema.new(JSI::JSON::ArrayNode.new(['foo'], pointer)), subject.select { |e| e == 'foo' }) }
176
188
  it('#select block var') do
177
189
  subj_a = subject.to_a
178
190
  subject.select { |e| assert_equal(e, subj_a.shift) }
@@ -183,7 +195,7 @@ describe JSI::BaseArray do
183
195
  let(:path) { ['1', 'c'] }
184
196
  it('#select') do
185
197
  selected = subject.select { |e| e == 'd' }
186
- equivalent_node = JSI::JSON::ArrayNode.new([['b', 'q'], {'c' => ['d']}], path)
198
+ equivalent_node = JSI::JSON::ArrayNode.new([['b', 'q'], {'c' => ['d']}], pointer)
187
199
  equivalent = class_for_schema.new(equivalent_node)
188
200
  assert_equal(equivalent, selected)
189
201
  end
@@ -5,7 +5,8 @@ describe JSI::BaseHash do
5
5
  {'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => true}
6
6
  end
7
7
  let(:path) { [] }
8
- let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
8
+ let(:pointer) { JSI::JSON::Pointer.new(path) }
9
+ let(:instance) { JSI::JSON::Node.new_by_type(document, pointer) }
9
10
  let(:schema_content) do
10
11
  {
11
12
  'type' => 'object',
@@ -137,43 +138,52 @@ describe JSI::BaseHash do
137
138
  it('#empty?') { assert_equal(false, subject.empty?) }
138
139
  it('#has_key?') { assert_equal(true, subject.has_key?('bar')) }
139
140
  it('#include?') { assert_equal(false, subject.include?('q')) }
140
- it('#key?') { assert_equal(true, subject.key?('baz')) }
141
- it('#keys') { assert_equal(['foo', 'bar', 'baz'], subject.keys) }
142
- it('#length') { assert_equal(3, subject.length) }
143
- it('#member?') { assert_equal(false, subject.member?(0)) }
144
- it('#size') { assert_equal(3, subject.size) }
141
+ it('#key?') { assert_equal(true, subject.key?('baz')) }
142
+ it('#keys') { assert_equal(['foo', 'bar', 'baz'], subject.keys) }
143
+ it('#length') { assert_equal(3, subject.length) }
144
+ it('#member?') { assert_equal(false, subject.member?(0)) }
145
+ it('#size') { assert_equal(3, subject.size) }
145
146
  end
146
147
  describe 'key + value methods' do
147
- it('#<') { assert_equal(true, subject < {'foo' => subject['foo'], 'bar' => subject['bar'], 'baz' => true, 'x' => 'y'}) } if {}.respond_to?(:<)
148
- it('#<=') { assert_equal(true, subject <= subject) } if {}.respond_to?(:<=)
149
- it('#>') { assert_equal(true, subject > {}) } if {}.respond_to?(:>)
150
- it('#>=') { assert_equal(false, subject >= {'foo' => 'bar'}) } if {}.respond_to?(:>=)
151
- it('#any?') { assert_equal(false, subject.any? { |k, v| v == 3 }) }
152
- it('#assoc') { assert_equal(['foo', subject['foo']], subject.assoc('foo')) }
153
- it('#dig') { assert_equal(9, subject.dig('bar', 0)) } if {}.respond_to?(:dig)
154
- it('#each_pair') { assert_equal([['foo', subject['foo']], ['bar', subject['bar']], ['baz', true]], subject.each_pair.to_a) }
155
- it('#each_value') { assert_equal([subject['foo'], subject['bar'], true], subject.each_value.to_a) }
156
- it('#fetch') { assert_equal(true, subject.fetch('baz')) }
148
+ it('#<') { assert_equal(true, subject < {'foo' => subject['foo'], 'bar' => subject['bar'], 'baz' => true, 'x' => 'y'}) } if {}.respond_to?(:<)
149
+ it('#<=') { assert_equal(true, subject <= subject) } if {}.respond_to?(:<=)
150
+ it('#>') { assert_equal(true, subject > {}) } if {}.respond_to?(:>)
151
+ it('#>=') { assert_equal(false, subject >= {'foo' => 'bar'}) } if {}.respond_to?(:>=)
152
+ it('#any?') { assert_equal(false, subject.any? { |k, v| v == 3 }) }
153
+ it('#assoc') { assert_equal(['foo', subject['foo']], subject.assoc('foo')) }
154
+ it('#dig') { assert_equal(9, subject.dig('bar', 0)) } if {}.respond_to?(:dig)
155
+ it('#each_pair') { assert_equal([['foo', subject['foo']], ['bar', subject['bar']], ['baz', true]], subject.each_pair.to_a) }
156
+ it('#each_value') { assert_equal([subject['foo'], subject['bar'], true], subject.each_value.to_a) }
157
+ it('#fetch') { assert_equal(true, subject.fetch('baz')) }
157
158
  it('#fetch_values') { assert_equal([true], subject.fetch_values('baz')) } if {}.respond_to?(:fetch_values)
158
- it('#has_value?') { assert_equal(true, subject.has_value?(true)) }
159
- it('#invert') { assert_equal({subject['foo'] => 'foo', subject['bar'] => 'bar', true => 'baz'}, subject.invert) }
160
- it('#key') { assert_equal('baz', subject.key(true)) }
161
- it('#rassoc') { assert_equal(['baz', true], subject.rassoc(true)) }
162
- it('#to_h') { assert_equal({'foo' => subject['foo'], 'bar' => subject['bar'], 'baz' => true}, subject.to_h) }
163
- it('#to_proc') { assert_equal(true, subject.to_proc.call('baz')) } if {}.respond_to?(:to_proc)
159
+ it('#has_value?') { assert_equal(true, subject.has_value?(true)) }
160
+ it('#invert') { assert_equal({subject['foo'] => 'foo', subject['bar'] => 'bar', true => 'baz'}, subject.invert) }
161
+ it('#key') { assert_equal('baz', subject.key(true)) }
162
+ it('#rassoc') { assert_equal(['baz', true], subject.rassoc(true)) }
163
+ it('#to_h') { assert_equal({'foo' => subject['foo'], 'bar' => subject['bar'], 'baz' => true}, subject.to_h) }
164
+ it('#to_proc') { assert_equal(true, subject.to_proc.call('baz')) } if {}.respond_to?(:to_proc)
164
165
  if {}.respond_to?(:transform_values)
165
166
  it('#transform_values') { assert_equal({'foo' => nil, 'bar' => nil, 'baz' => nil}, subject.transform_values { |_| nil }) }
166
167
  end
167
- it('#value?') { assert_equal(false, subject.value?('0')) }
168
- it('#values') { assert_equal([subject['foo'], subject['bar'], true], subject.values) }
169
- it('#values_at') { assert_equal([true], subject.values_at('baz')) }
168
+ it('#value?') { assert_equal(false, subject.value?('0')) }
169
+ it('#values') { assert_equal([subject['foo'], subject['bar'], true], subject.values) }
170
+ it('#values_at') { assert_equal([true], subject.values_at('baz')) }
171
+ end
172
+ describe 'with an instance that has to_hash but not other hash instance methods' do
173
+ let(:instance) { SortOfHash.new({'foo' => SortOfHash.new({'a' => 'b'})}) }
174
+ describe 'delegating instance methods to #to_hash' do
175
+ it('#each_key') { assert_equal(['foo'], subject.each_key.to_a) }
176
+ it('#each_pair') { assert_equal([['foo', subject['foo']]], subject.each_pair.to_a) }
177
+ it('#[]') { assert_equal(SortOfHash.new({'a' => 'b'}), subject['foo'].instance) }
178
+ it('#as_json') { assert_equal({'foo' => {'a' => 'b'}}, subject.as_json) }
179
+ end
170
180
  end
171
181
  describe 'modified copy methods' do
172
182
  # I'm going to rely on the #merge test above to test the modified copy functionality and just do basic
173
183
  # tests of all the modified copy methods here
174
- it('#merge') { assert_equal(subject, subject.merge({})) }
175
- it('#reject') { assert_equal(class_for_schema.new(JSI::JSON::HashNode.new({}, [])), subject.reject { true }) }
176
- it('#select') { assert_equal(class_for_schema.new(JSI::JSON::HashNode.new({}, [])), subject.select { false }) }
184
+ it('#merge') { assert_equal(subject, subject.merge({})) }
185
+ it('#reject') { assert_equal(class_for_schema.new(JSI::JSON::HashNode.new({}, pointer)), subject.reject { true }) }
186
+ it('#select') { assert_equal(class_for_schema.new(JSI::JSON::HashNode.new({}, pointer)), subject.select { false }) }
177
187
  describe '#select' do
178
188
  it 'yields properly too' do
179
189
  subject.select do |k, v|
@@ -5,7 +5,8 @@ NamedSchemaInstance = JSI.class_for_schema({id: 'https://schemas.jsi.unth.net/te
5
5
  describe JSI::Base do
6
6
  let(:document) { {} }
7
7
  let(:path) { [] }
8
- let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
8
+ let(:pointer) { JSI::JSON::Pointer.new(path) }
9
+ let(:instance) { JSI::JSON::Node.new_by_type(document, pointer) }
9
10
  let(:schema_content) { {} }
10
11
  let(:schema) { JSI::Schema.new(schema_content) }
11
12
  let(:subject) { JSI.class_for_schema(schema).new(instance) }
@@ -107,7 +108,7 @@ describe JSI::Base do
107
108
  describe 'nil' do
108
109
  let(:instance) { nil }
109
110
  it 'initializes with nil instance' do
110
- assert_equal(JSI::JSON::Node.new_doc(nil), subject.instance)
111
+ assert_equal(nil, subject.instance)
111
112
  assert(!subject.respond_to?(:to_ary))
112
113
  assert(!subject.respond_to?(:to_hash))
113
114
  end
@@ -115,7 +116,7 @@ describe JSI::Base do
115
116
  describe 'arbitrary instance' do
116
117
  let(:instance) { Object.new }
117
118
  it 'initializes' do
118
- assert_equal(JSI::JSON::Node.new_doc(instance), subject.instance)
119
+ assert_equal(instance, subject.instance)
119
120
  assert(!subject.respond_to?(:to_ary))
120
121
  assert(!subject.respond_to?(:to_hash))
121
122
  end
@@ -124,7 +125,7 @@ describe JSI::Base do
124
125
  let(:instance) { {'foo' => 'bar'} }
125
126
  let(:schema_content) { {'type' => 'object'} }
126
127
  it 'initializes' do
127
- assert_equal(JSI::JSON::Node.new_doc({'foo' => 'bar'}), subject.instance)
128
+ assert_equal({'foo' => 'bar'}, subject.instance)
128
129
  assert(!subject.respond_to?(:to_ary))
129
130
  assert(subject.respond_to?(:to_hash))
130
131
  end
@@ -133,7 +134,7 @@ describe JSI::Base do
133
134
  let(:document) { {'foo' => 'bar'} }
134
135
  let(:schema_content) { {'type' => 'object'} }
135
136
  it 'initializes' do
136
- assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, []), subject.instance)
137
+ assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])), subject.instance)
137
138
  assert(!subject.respond_to?(:to_ary))
138
139
  assert(subject.respond_to?(:to_hash))
139
140
  end
@@ -142,7 +143,7 @@ describe JSI::Base do
142
143
  let(:instance) { ['foo'] }
143
144
  let(:schema_content) { {'type' => 'array'} }
144
145
  it 'initializes' do
145
- assert_equal(JSI::JSON::Node.new_doc(['foo']), subject.instance)
146
+ assert_equal(['foo'], subject.instance)
146
147
  assert(subject.respond_to?(:to_ary))
147
148
  assert(!subject.respond_to?(:to_hash))
148
149
  end
@@ -151,41 +152,52 @@ describe JSI::Base do
151
152
  let(:document) { ['foo'] }
152
153
  let(:schema_content) { {'type' => 'array'} }
153
154
  it 'initializes' do
154
- assert_equal(JSI::JSON::ArrayNode.new(['foo'], []), subject.instance)
155
+ assert_equal(JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])), subject.instance)
155
156
  assert(subject.respond_to?(:to_ary))
156
157
  assert(!subject.respond_to?(:to_hash))
157
158
  end
158
159
  end
159
- describe 'another Base' do
160
+ describe 'another JSI::Base invalid' do
160
161
  let(:schema_content) { {'type' => 'object'} }
161
162
  let(:instance) { JSI.class_for_schema(schema).new({'foo' => 'bar'}) }
162
- it 'initializes with a warning' do
163
- assert_output(nil, /assigning instance to a Base instance is incorrect. received: #\{<JSI::SchemaClasses\["[^"]+#"\][^>]*>[^}]+}/) do
164
- subject
165
- end
166
- assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, []), subject.instance)
163
+ it 'initializes with an error' do
164
+ err = assert_raises(TypeError) { subject }
165
+ assert_match(%r(\Aassigning another JSI::Base instance to JSI::SchemaClasses\[\".*#\"\] instance is incorrect. received: #\{<JSI::SchemaClasses\[.*\] Hash>\s*"foo" => "bar"\s*\}\z)m, err.message)
166
+ end
167
+ end
168
+ describe 'Schema invalid' do
169
+ let(:instance) { JSI::Schema.new({}) }
170
+ it 'initializes with an error' do
171
+ err = assert_raises(TypeError) { subject }
172
+ assert_match(%r(\Aassigning a schema to JSI::SchemaClasses\[\".*#\"\] instance is incorrect. received: #<JSI::Schema schema_id=.*>\z)m, err.message)
167
173
  end
168
174
  end
169
175
  end
170
- describe '#parents, #parent' do
176
+ describe '#parent_jsis, #parent_jsi' do
171
177
  let(:schema_content) { {'properties' => {'foo' => {'properties' => {'bar' => {'properties' => {'baz' => {}}}}}}} }
172
178
  let(:document) { {'foo' => {'bar' => {'baz' => {}}}} }
173
- describe 'no parents' do
179
+ describe 'no parent_jsis' do
174
180
  it 'has none' do
175
181
  assert_equal([], subject.parents)
182
+ assert_equal([], subject.parent_jsis.to_a)
176
183
  assert_equal(nil, subject.parent)
184
+ assert_equal(nil, subject.parent_jsi)
177
185
  end
178
186
  end
179
- describe 'one parent' do
187
+ describe 'one parent_jsi' do
180
188
  it 'has one' do
181
189
  assert_equal([subject], subject.foo.parents)
190
+ assert_equal([subject], subject.foo.parent_jsis.to_a)
182
191
  assert_equal(subject, subject.foo.parent)
192
+ assert_equal(subject, subject.foo.parent_jsi)
183
193
  end
184
194
  end
185
- describe 'more parents' do
195
+ describe 'more parent_jsis' do
186
196
  it 'has more' do
187
197
  assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parents)
198
+ assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parent_jsis.to_a)
188
199
  assert_equal(subject.foo.bar, subject.foo.bar.baz.parent)
200
+ assert_equal(subject.foo.bar, subject.foo.bar.baz.parent_jsi)
189
201
  end
190
202
  end
191
203
  end
@@ -197,6 +209,19 @@ describe JSI::Base do
197
209
  end
198
210
  end
199
211
  describe '#modified_copy' do
212
+ describe 'with an instance that does not have #modified_copy' do
213
+ let(:instance) { Object.new }
214
+ it 'yields the instance to modify' do
215
+ new_instance = Object.new
216
+ modified = subject.modified_copy do |o|
217
+ assert_equal(instance, o)
218
+ new_instance
219
+ end
220
+ assert_equal(new_instance, modified.instance)
221
+ assert_equal(instance, subject.instance)
222
+ refute_equal(instance, modified)
223
+ end
224
+ end
200
225
  describe 'with an instance that does have #modified_copy' do
201
226
  it 'yields the instance to modify' do
202
227
  modified = subject.modified_copy do |o|
@@ -282,7 +307,7 @@ describe JSI::Base do
282
307
  let(:instance) { nil }
283
308
  it 'errors' do
284
309
  err = assert_raises(NoMethodError) { subject.foo }
285
- assert_match(%r(\Ainstance does not respond to \[\]; cannot call reader `foo' for: #<JSI::SchemaClasses\["[^"]+#"\].*nil.*>\z)m, err.message)
310
+ assert_match(%r(\Aschema instance of class .* does not respond to \[\]; cannot call reader 'foo'. instance is )m, err.message)
286
311
  end
287
312
  end
288
313
  describe 'properties with the same names as instance methods' do
@@ -317,7 +342,7 @@ describe JSI::Base do
317
342
  end
318
343
  it 'does not define readers' do
319
344
  assert_equal('bar', subject.foo)
320
- assert_equal(JSI::SchemaClasses.module_for_schema(subject.schema), subject.method(:foo).owner)
345
+ assert_equal(JSI::SchemaClasses.module_for_schema(subject.schema, conflicting_modules: [JSI::Base, JSI::BaseArray, JSI::BaseHash]), subject.method(:foo).owner)
321
346
 
322
347
  assert_equal(JSI::Base, subject.method(:initialize).owner)
323
348
  assert_equal('hi', subject['initialize'])
@@ -356,7 +381,7 @@ describe JSI::Base do
356
381
  let(:instance) { nil }
357
382
  it 'errors' do
358
383
  err = assert_raises(NoMethodError) { subject.foo = 0 }
359
- assert_match(%r(\Ainstance does not respond to \[\]=; cannot call writer `foo=' for: #<JSI::SchemaClasses\["[^"]+#"\].*nil.*>\z)m, err.message)
384
+ assert_match(%r(\Aschema instance of class .* does not respond to \[\]=; cannot call writer 'foo='. instance is )m, err.message)
360
385
  end
361
386
  end
362
387
  end
@@ -383,13 +408,15 @@ describe JSI::Base do
383
408
  assert_equal(['a'], JSI.class_for_schema({}).new(['a']).as_json(some_option: true))
384
409
  end
385
410
  end
386
- describe 'overwrite schema instance with instance=' do
387
- # this error message indicates an internal bug (hence Bug class), so there isn't an intended way to
388
- # trigger it using JSI::Base properly. we use it improperly just to test that code path. this
389
- # is definitely not defined behavior.
390
- it 'errors' do
391
- err = assert_raises(JSI::Bug) { subject.send(:instance=, {'foo' => 'bar'}) }
392
- assert_match(%r(\Aoverwriting instance is not supported\z), err.message)
411
+ describe 'equality between different classes of JSI::Base subclasses' do
412
+ let(:subject_subclass) { Class.new(JSI.class_for_schema(schema)).new(instance) }
413
+
414
+ it 'considers a Base subclass (class_for_schema) and subsubclass to be equal with the same instance' do
415
+ assert_equal(subject.hash, subject_subclass.hash)
416
+ assert(subject == subject_subclass)
417
+ assert(subject_subclass == subject)
418
+ assert(subject.eql?(subject_subclass))
419
+ assert(subject_subclass.eql?(subject))
393
420
  end
394
421
  end
395
422
  end
@@ -18,8 +18,9 @@ document_types.each do |document_type|
18
18
  let(:document) { document_type[:document] }
19
19
  # by default the node is the whole document
20
20
  let(:path) { [] }
21
+ let(:pointer) { JSI::JSON::Pointer.new(path) }
21
22
  # the node being tested
22
- let(:node) { JSI::JSON::Node.new_by_type(document, path) }
23
+ let(:node) { JSI::JSON::Node.new_by_type(document, pointer) }
23
24
 
24
25
  describe '#[] bad index' do
25
26
  it 'improves TypeError for Array subsript' do
@@ -107,24 +108,24 @@ document_types.each do |document_type|
107
108
  # for this reason, rassoc is NOT defined on Arraylike. it's here with as_json.
108
109
  #
109
110
  # I've never even seen anybody use rassoc. of all the methods to put into the standard library ...
110
- it('#rassoc') { assert_equal(['b', 'q'], node.as_json.rassoc('q')) }
111
+ it('#rassoc') { assert_equal(['b', 'q'], node.as_json.rassoc('q')) }
111
112
  it('#repeated_combination') { assert_equal([[]], node.repeated_combination(0).to_a) }
112
113
  it('#repeated_permutation') { assert_equal([[]], node.repeated_permutation(0).to_a) }
113
- it('#reverse') { assert_equal([node[2], node[1], 'a'], node.reverse) }
114
- it('#reverse_each') { assert_equal([node[2], node[1], 'a'], node.reverse_each.to_a) }
115
- it('#rindex') { assert_equal(0, node.rindex('a')) }
116
- it('#rotate') { assert_equal([node[1], node[2], 'a'], node.rotate) }
117
- it('#sample') { assert_equal('a', JSI::JSON::Node.new_doc(['a']).sample) }
118
- it('#shelljoin') { assert_equal('a', JSI::JSON::Node.new_doc(['a']).shelljoin) } if [].respond_to?(:shelljoin)
119
- it('#shuffle') { assert_equal(3, node.shuffle.size) }
120
- it('#slice') { assert_equal(['a'], node.slice(0, 1)) }
121
- it('#sort') { assert_equal(['a'], JSI::JSON::Node.new_doc(['a']).sort) }
122
- it('#take') { assert_equal(['a'], node.take(1)) }
123
- it('#take_while') { assert_equal([], node.take_while { false }) }
124
- it('#transpose') { assert_equal([], JSI::JSON::Node.new_doc([]).transpose) }
125
- it('#uniq') { assert_equal(node.to_a, node.uniq) }
126
- it('#values_at') { assert_equal(['a'], node.values_at(0)) }
127
- it('#zip') { assert_equal([['a', 'a'], [node[1], node[1]], [node[2], node[2]]], node.zip(node)) }
114
+ it('#reverse') { assert_equal([node[2], node[1], 'a'], node.reverse) }
115
+ it('#reverse_each') { assert_equal([node[2], node[1], 'a'], node.reverse_each.to_a) }
116
+ it('#rindex') { assert_equal(0, node.rindex('a')) }
117
+ it('#rotate') { assert_equal([node[1], node[2], 'a'], node.rotate) }
118
+ it('#sample') { assert_equal('a', JSI::JSON::Node.new_doc(['a']).sample) }
119
+ it('#shelljoin') { assert_equal('a', JSI::JSON::Node.new_doc(['a']).shelljoin) } if [].respond_to?(:shelljoin)
120
+ it('#shuffle') { assert_equal(3, node.shuffle.size) }
121
+ it('#slice') { assert_equal(['a'], node.slice(0, 1)) }
122
+ it('#sort') { assert_equal(['a'], JSI::JSON::Node.new_doc(['a']).sort) }
123
+ it('#take') { assert_equal(['a'], node.take(1)) }
124
+ it('#take_while') { assert_equal([], node.take_while { false }) }
125
+ it('#transpose') { assert_equal([], JSI::JSON::Node.new_doc([]).transpose) }
126
+ it('#uniq') { assert_equal(node.to_a, node.uniq) }
127
+ it('#values_at') { assert_equal(['a'], node.values_at(0)) }
128
+ it('#zip') { assert_equal([['a', 'a'], [node[1], node[1]], [node[2], node[2]]], node.zip(node)) }
128
129
  end
129
130
  describe 'modified copy methods' do
130
131
  it('#reject') { assert_equal(JSI::JSON::Node.new_doc(['a']), node.reject { |e| e != 'a' }) }
@@ -135,7 +136,7 @@ document_types.each do |document_type|
135
136
  let(:path) { ['1', 'c'] }
136
137
  it('#select') do
137
138
  selected = node.select { |e| e == 'd' }
138
- equivalent = JSI::JSON::Node.new_by_type([['b', 'q'], {'c' => ['d']}], ['1', 'c'])
139
+ equivalent = JSI::JSON::Node.new_by_type([['b', 'q'], {'c' => ['d']}], pointer)
139
140
  assert_equal(equivalent, selected)
140
141
  end
141
142
  end