jsi 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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