jsi 0.0.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +3 -1
  3. data/CHANGELOG.md +48 -0
  4. data/LICENSE.md +613 -0
  5. data/README.md +84 -45
  6. data/jsi.gemspec +11 -14
  7. data/lib/jsi.rb +31 -12
  8. data/lib/jsi/base.rb +310 -344
  9. data/lib/jsi/base/to_rb.rb +2 -0
  10. data/lib/jsi/jsi_coder.rb +91 -0
  11. data/lib/jsi/json-schema-fragments.rb +3 -135
  12. data/lib/jsi/json.rb +3 -0
  13. data/lib/jsi/json/node.rb +72 -197
  14. data/lib/jsi/json/pointer.rb +419 -0
  15. data/lib/jsi/metaschema.rb +7 -0
  16. data/lib/jsi/metaschema_node.rb +218 -0
  17. data/lib/jsi/pathed_node.rb +118 -0
  18. data/lib/jsi/schema.rb +168 -223
  19. data/lib/jsi/schema_classes.rb +158 -0
  20. data/lib/jsi/simple_wrap.rb +12 -0
  21. data/lib/jsi/typelike_modules.rb +71 -45
  22. data/lib/jsi/util.rb +47 -57
  23. data/lib/jsi/version.rb +1 -1
  24. data/lib/schemas/json-schema.org/draft-04/schema.rb +7 -0
  25. data/lib/schemas/json-schema.org/draft-06/schema.rb +7 -0
  26. data/resources/icons/AGPL-3.0.png +0 -0
  27. data/test/base_array_test.rb +210 -84
  28. data/test/base_hash_test.rb +201 -58
  29. data/test/base_test.rb +212 -121
  30. data/test/jsi_coder_test.rb +85 -0
  31. data/test/jsi_json_arraynode_test.rb +26 -25
  32. data/test/jsi_json_hashnode_test.rb +40 -39
  33. data/test/jsi_json_node_test.rb +95 -126
  34. data/test/jsi_json_pointer_test.rb +102 -0
  35. data/test/jsi_typelike_as_json_test.rb +53 -0
  36. data/test/metaschema_node_test.rb +19 -0
  37. data/test/schema_module_test.rb +21 -0
  38. data/test/schema_test.rb +109 -97
  39. data/test/spreedly_openapi_test.rb +8 -0
  40. data/test/test_helper.rb +42 -8
  41. data/test/util_test.rb +14 -14
  42. metadata +54 -25
  43. data/LICENSE.txt +0 -21
  44. data/lib/jsi/schema_instance_json_coder.rb +0 -83
  45. data/lib/jsi/struct_json_coder.rb +0 -30
  46. data/test/schema_instance_json_coder_test.rb +0 -121
  47. data/test/struct_json_coder_test.rb +0 -130
@@ -1,3 +1,3 @@
1
1
  module JSI
2
- VERSION = "0.0.4".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ schema_id = 'http://json-schema.org/draft-04/schema'
5
+ schema_content = ::JSON.parse(File.read(::JSON::Validator.validators[schema_id].metaschema))
6
+ JSONSchemaOrgDraft04 = MetaschemaNode.new(schema_content).jsi_schema_module
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSI
4
+ schema_id = 'http://json-schema.org/draft/schema' # I don't know why this is not http://json-schema.org/draft-06/schema
5
+ schema_content = ::JSON.parse(File.read(::JSON::Validator.validators[schema_id].metaschema))
6
+ JSONSchemaOrgDraft06 = MetaschemaNode.new(schema_content).jsi_schema_module
7
+ end
@@ -1,24 +1,32 @@
1
1
  require_relative 'test_helper'
2
2
 
3
- describe JSI::BaseArray do
4
- let(:document) do
5
- ['foo', {'lamp' => [3]}, ['q', 'r']]
6
- end
7
- let(:path) { [] }
8
- let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
3
+ base = {
4
+ 'description' => 'named array schema',
5
+ 'type' => 'array',
6
+ 'items' => [
7
+ {'type' => 'string'},
8
+ {'type' => 'object'},
9
+ {'type' => 'array', 'items' => {}},
10
+ ],
11
+ }
12
+ NamedArrayInstance = JSI::Schema.new(base).jsi_schema_class
13
+ NamedIdArrayInstance = JSI::Schema.new({'$id' => 'https://schemas.jsi.unth.net/test/base/named_array_schema'}.merge(base)).jsi_schema_class
14
+
15
+ describe 'JSI::Base array' do
16
+ let(:instance) { ['foo', {'lamp' => [3]}, ['q', 'r'], {'four' => 4}] }
9
17
  let(:schema_content) do
10
18
  {
19
+ 'description' => 'hash schema',
11
20
  'type' => 'array',
12
21
  'items' => [
13
22
  {'type' => 'string'},
14
- {'type' => 'object', 'items' => {}},
15
- {'type' => 'array'},
23
+ {'type' => 'object'},
24
+ {'type' => 'array', 'items' => {}},
16
25
  ],
17
26
  }
18
27
  end
19
28
  let(:schema) { JSI::Schema.new(schema_content) }
20
- let(:class_for_schema) { JSI.class_for_schema(schema) }
21
- let(:subject) { class_for_schema.new(instance) }
29
+ let(:subject) { schema.new_jsi(instance) }
22
30
 
23
31
  describe '#[] with a default that is a basic type' do
24
32
  let(:schema_content) do
@@ -28,21 +36,21 @@ describe JSI::BaseArray do
28
36
  }
29
37
  end
30
38
  describe 'default value' do
31
- let(:document) { [1] }
39
+ let(:instance) { [1] }
32
40
  it 'returns the default value' do
33
41
  assert_equal('foo', subject[2])
34
42
  end
35
43
  end
36
44
  describe 'nondefault value (basic type)' do
37
- let(:document) { ['who'] }
45
+ let(:instance) { ['who'] }
38
46
  it 'returns the nondefault value' do
39
47
  assert_equal('who', subject[0])
40
48
  end
41
49
  end
42
50
  describe 'nondefault value (nonbasic type)' do
43
- let(:document) { [[2]] }
51
+ let(:instance) { [[2]] }
44
52
  it 'returns the nondefault value' do
45
- assert_instance_of(JSI.class_for_schema(schema['items']), subject[0])
53
+ assert_is_a(schema.items.jsi_schema_module, subject[0])
46
54
  assert_equal([2], subject[0].as_json)
47
55
  end
48
56
  end
@@ -55,22 +63,22 @@ describe JSI::BaseArray do
55
63
  }
56
64
  end
57
65
  describe 'default value' do
58
- let(:document) { [{'bar' => 3}] }
66
+ let(:instance) { [{'bar' => 3}] }
59
67
  it 'returns the default value' do
60
- assert_instance_of(JSI.class_for_schema(schema['items']), subject[1])
68
+ assert_is_a(schema.items.jsi_schema_module, subject[1])
61
69
  assert_equal({'foo' => 2}, subject[1].as_json)
62
70
  end
63
71
  end
64
72
  describe 'nondefault value (basic type)' do
65
- let(:document) { [true, 'who'] }
73
+ let(:instance) { [true, 'who'] }
66
74
  it 'returns the nondefault value' do
67
75
  assert_equal('who', subject[1])
68
76
  end
69
77
  end
70
78
  describe 'nondefault value (nonbasic type)' do
71
- let(:document) { [true, [2]] }
79
+ let(:instance) { [true, [2]] }
72
80
  it 'returns the nondefault value' do
73
- assert_instance_of(JSI.class_for_schema(schema['items']), subject[1])
81
+ assert_is_a(schema.items.jsi_schema_module, subject[1])
74
82
  assert_equal([2], subject[1].as_json)
75
83
  end
76
84
  end
@@ -82,110 +90,228 @@ describe JSI::BaseArray do
82
90
  subject[2] = {'y' => 'z'}
83
91
 
84
92
  assert_equal({'y' => 'z'}, subject[2].as_json)
85
- assert_instance_of(JSI.class_for_schema(schema.schema_node['items'][2]), orig_2)
86
- assert_instance_of(JSI.class_for_schema(schema.schema_node['items'][2]), subject[2])
93
+ assert_is_a(schema.items[2].jsi_schema_module, orig_2)
94
+ assert_is_a(schema.items[2].jsi_schema_module, subject[2])
87
95
  end
88
96
  it 'modifies the instance, visible to other references to the same instance' do
89
- orig_instance = subject.instance
97
+ orig_instance = subject.jsi_instance
90
98
 
91
99
  subject[2] = {'y' => 'z'}
92
100
 
93
- assert_equal(orig_instance, subject.instance)
94
- assert_equal({'y' => 'z'}, orig_instance[2].as_json)
95
- assert_equal({'y' => 'z'}, subject.instance[2].as_json)
96
- assert_equal(orig_instance.class, subject.instance.class)
101
+ assert_equal(orig_instance, subject.jsi_instance)
102
+ assert_equal({'y' => 'z'}, orig_instance[2])
103
+ assert_equal({'y' => 'z'}, subject.jsi_instance[2])
104
+ assert_equal(orig_instance.class, subject.jsi_instance.class)
97
105
  end
98
106
  describe 'when the instance is not arraylike' do
99
107
  let(:instance) { nil }
100
108
  it 'errors' do
101
109
  err = assert_raises(NoMethodError) { subject[2] = 0 }
102
- assert_match(%r(\Aundefined method `\[\]=' for #<JSI::SchemaClasses::X.*>\z), err.message)
110
+ assert_equal("cannot assign subcript (using token: 2) to instance: nil", err.message)
111
+ end
112
+ end
113
+ describe '#inspect' do
114
+ it 'inspects' do
115
+ assert_equal("#[<JSI> \"foo\", \#{<JSI> \"lamp\" => [3]}, #[<JSI> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
116
+ end
117
+ end
118
+ describe '#pretty_print' do
119
+ it 'pretty_prints' do
120
+ assert_equal("#[<JSI> \"foo\", \#{<JSI> \"lamp\" => [3]}, #[<JSI> \"q\", \"r\"], {\"four\"=>4}]\n", subject.pretty_inspect)
121
+ end
122
+ end
123
+ describe '#inspect SortOfArray' do
124
+ let(:subject) { schema.new_jsi(SortOfArray.new(instance)) }
125
+ it 'inspects' do
126
+ assert_equal("#[<JSI SortOfArray> \"foo\", \#{<JSI> \"lamp\" => [3]}, #[<JSI> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
127
+ end
128
+ end
129
+ describe '#pretty_print SortOfArray' do
130
+ let(:subject) { schema.new_jsi(SortOfArray.new(instance)) }
131
+ it 'pretty_prints' do
132
+ assert_equal("#[<JSI SortOfArray>\n \"foo\",\n \#{<JSI> \"lamp\" => [3]},\n #[<JSI> \"q\", \"r\"],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
133
+ end
134
+ end
135
+ describe '#inspect named' do
136
+ let(:subject) { NamedArrayInstance.new(instance) }
137
+ it 'inspects' do
138
+ assert_equal("#[<NamedArrayInstance> \"foo\", \#{<JSI> \"lamp\" => [3]}, #[<JSI> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
139
+ end
140
+ end
141
+ describe '#pretty_print named' do
142
+ let(:subject) { NamedArrayInstance.new(instance) }
143
+ it 'inspects' do
144
+ assert_equal("#[<NamedArrayInstance>\n \"foo\",\n \#{<JSI> \"lamp\" => [3]},\n #[<JSI> \"q\", \"r\"],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
145
+ end
146
+ end
147
+ describe '#inspect named SortOfArray' do
148
+ let(:subject) { NamedArrayInstance.new(SortOfArray.new(instance)) }
149
+ it 'inspects' do
150
+ assert_equal("#[<NamedArrayInstance SortOfArray> \"foo\", \#{<JSI> \"lamp\" => [3]}, #[<JSI> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
151
+ end
152
+ end
153
+ describe '#pretty_print named SortOfArray' do
154
+ let(:subject) { NamedArrayInstance.new(SortOfArray.new(instance)) }
155
+ it 'inspects' do
156
+ assert_equal("#[<NamedArrayInstance SortOfArray>\n \"foo\",\n \#{<JSI> \"lamp\" => [3]},\n #[<JSI> \"q\", \"r\"],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
157
+ end
158
+ end
159
+ describe '#inspect named with id' do
160
+ let(:subject) { NamedIdArrayInstance.new(instance) }
161
+ it 'inspects' do
162
+ assert_equal("#[<NamedIdArrayInstance> \"foo\", \#{<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/1)> \"lamp\" => [3]}, #[<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/2)> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
163
+ end
164
+ end
165
+ describe '#pretty_print named with id' do
166
+ let(:subject) { NamedIdArrayInstance.new(instance) }
167
+ it 'inspects' do
168
+ assert_equal("#[<NamedIdArrayInstance>\n \"foo\",\n \#{<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/1)>\n \"lamp\" => [3]\n },\n #[<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/2)>\n \"q\",\n \"r\"\n ],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
169
+ end
170
+ end
171
+ describe '#inspect named with id SortOfArray' do
172
+ let(:subject) { NamedIdArrayInstance.new(SortOfArray.new(instance)) }
173
+ it 'inspects' do
174
+ assert_equal("#[<NamedIdArrayInstance SortOfArray> \"foo\", \#{<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/1)> \"lamp\" => [3]}, #[<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/2)> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
175
+ end
176
+ end
177
+ describe '#pretty_print named with id SortOfArray' do
178
+ let(:subject) { NamedIdArrayInstance.new(SortOfArray.new(instance)) }
179
+ it 'inspects' do
180
+ assert_equal("#[<NamedIdArrayInstance SortOfArray>\n \"foo\",\n \#{<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/1)>\n \"lamp\" => [3]\n },\n #[<JSI (https://schemas.jsi.unth.net/test/base/named_array_schema#/items/2)>\n \"q\",\n \"r\"\n ],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
181
+ end
182
+ end
183
+ describe '#inspect with id' do
184
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_array_test/withid', 'items' => [{}, {}, {}]} }
185
+ let(:subject) { schema.new_jsi(instance) }
186
+ it 'inspects' do
187
+ assert_equal("#[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#)> \"foo\", \#{<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/1)> \"lamp\" => [3]}, #[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/2)> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
188
+ end
189
+ end
190
+ describe '#pretty_print with id' do
191
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_array_test/withid', 'items' => [{}, {}, {}]} }
192
+ let(:subject) { schema.new_jsi(instance) }
193
+ it 'pretty prints' do
194
+ assert_equal("#[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#)>\n \"foo\",\n \#{<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/1)>\n \"lamp\" => [3]\n },\n #[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/2)>\n \"q\",\n \"r\"\n ],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
195
+ end
196
+ end
197
+ describe '#inspect with id SortOfArray' do
198
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_array_test/withid', 'items' => [{}, {}, {}]} }
199
+ let(:subject) { schema.new_jsi(SortOfArray.new(instance)) }
200
+ it 'inspects' do
201
+ assert_equal("#[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#) SortOfArray> \"foo\", \#{<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/1)> \"lamp\" => [3]}, #[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/2)> \"q\", \"r\"], {\"four\"=>4}]", subject.inspect)
202
+ end
203
+ end
204
+ describe '#pretty_print with id SortOfArray' do
205
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_array_test/withid', 'items' => [{}, {}, {}]} }
206
+ let(:subject) { schema.new_jsi(SortOfArray.new(instance)) }
207
+ it 'inspects' do
208
+ assert_equal("#[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#) SortOfArray>\n \"foo\",\n \#{<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/1)>\n \"lamp\" => [3]\n },\n #[<JSI (https://schemas.jsi.unth.net/base_array_test/withid#/items/2)>\n \"q\",\n \"r\"\n ],\n {\"four\"=>4}\n]\n", subject.pretty_inspect)
209
+ end
210
+ end
211
+ describe '#inspect Node' do
212
+ let(:subject) { schema.new_jsi(JSI::JSON::Node.new_doc(instance)) }
213
+ it 'inspects' do
214
+ assert_equal("#[<JSI JSI::JSON::ArrayNode #> \"foo\", \#{<JSI JSI::JSON::HashNode #/1> \"lamp\" => #[<JSI::JSON::ArrayNode #/1/lamp> 3]}, #[<JSI JSI::JSON::ArrayNode #/2> \"q\", \"r\"], \#{<JSI::JSON::HashNode #/3> \"four\" => 4}]", subject.inspect)
215
+ end
216
+ end
217
+ describe '#pretty_print Node' do
218
+ let(:subject) { schema.new_jsi(JSI::JSON::Node.new_doc(instance)) }
219
+ it 'pretty_prints' do
220
+ assert_equal("#[<JSI JSI::JSON::ArrayNode #>\n \"foo\",\n \#{<JSI JSI::JSON::HashNode #/1>\n \"lamp\" => #[<JSI::JSON::ArrayNode #/1/lamp> 3]\n },\n #[<JSI JSI::JSON::ArrayNode #/2> \"q\", \"r\"],\n \#{<JSI::JSON::HashNode #/3> \"four\" => 4}\n]\n", subject.pretty_inspect)
103
221
  end
104
222
  end
105
223
  end
106
224
  # these methods just delegate to Array so not going to test excessively
107
225
  describe 'index only methods' do
108
- 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) }
226
+ it('#each_index') { assert_equal([0, 1, 2, 3], subject.each_index.to_a) }
227
+ it('#empty?') { assert_equal(false, subject.empty?) }
228
+ it('#length') { assert_equal(4, subject.length) }
229
+ it('#size') { assert_equal(4, subject.size) }
112
230
  end
113
231
  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) }
232
+ it('#|') { assert_equal(['foo', subject[1], subject[2], subject[3], 0], subject | [0]) }
233
+ it('#&') { assert_equal(['foo'], subject & ['foo']) }
234
+ it('#*') { assert_equal(subject.to_a, subject * 1) }
235
+ it('#+') { assert_equal(subject.to_a, subject + []) }
236
+ it('#-') { assert_equal([subject[1], subject[2], subject[3]], subject - ['foo']) }
237
+ it('#<=>') { assert_equal(1, subject <=> []) }
238
+ it('#<=>') { assert_equal(-1, [] <=> subject) }
121
239
  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([])) }
240
+ it('#abbrev') { assert_equal({'a' => 'a'}, schema.new_jsi(['a']).abbrev) }
241
+ it('#assoc') { assert_equal(['q', 'r'], subject.assoc('q')) }
242
+ it('#at') { assert_equal('foo', subject.at(0)) }
243
+ it('#bsearch') { assert_equal(nil, subject.bsearch { false }) }
244
+ it('#bsearch_index') { assert_equal(nil, subject.bsearch_index { false }) } if [].respond_to?(:bsearch_index)
245
+ it('#combination') { assert_equal([['foo'], [subject[1]], [subject[2]], [subject[3]]], subject.combination(1).to_a) }
246
+ it('#count') { assert_equal(1, subject.count('foo')) }
247
+ it('#cycle') { assert_equal(subject.to_a, subject.cycle(1).to_a) }
248
+ it('#dig') { assert_equal(3, subject.dig(1, 'lamp', 0)) } if [].respond_to?(:dig)
249
+ it('#drop') { assert_equal([subject[2], subject[3]], subject.drop(2)) }
250
+ it('#drop_while') { assert_equal([subject[1], subject[2], subject[3]], subject.drop_while { |e| e == 'foo' }) }
251
+ it('#fetch') { assert_equal('foo', subject.fetch(0)) }
252
+ it('#find_index') { assert_equal(0, subject.find_index { true }) }
253
+ it('#first') { assert_equal('foo', subject.first) }
254
+ it('#include?') { assert_equal(true, subject.include?('foo')) }
255
+ it('#index') { assert_equal(0, subject.index('foo')) }
256
+ it('#join') { assert_equal('a b', schema.new_jsi(['a', 'b']).join(' ')) }
257
+ it('#last') { assert_equal(subject[3], subject.last) }
258
+ it('#pack') { assert_equal(' ', schema.new_jsi([32]).pack('c')) }
259
+ it('#permutation') { assert_equal([['foo'], [subject[1]], [subject[2]], [subject[3]]], subject.permutation(1).to_a) }
260
+ it('#product') { assert_equal([], subject.product([])) }
143
261
  # due to differences in implementation between #assoc and #rassoc, the reason for which
144
262
  # I cannot begin to fathom, assoc works but rassoc does not because rassoc has different
145
263
  # type checking than assoc for the array(like) array elements.
146
264
  # compare:
147
265
  # assoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3780-L3813
148
266
  # rassoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3815-L3847
149
- # 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')) }
267
+ # for this reason, rassoc is NOT defined on Arraylike and we call #jsi_instance to use it.
268
+ it('#rassoc') { assert_equal(['q', 'r'], subject.jsi_instance.rassoc('r')) }
151
269
  it('#repeated_combination') { assert_equal([[]], subject.repeated_combination(0).to_a) }
152
270
  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)) }
271
+ it('#reverse') { assert_equal([subject[3], subject[2], subject[1], 'foo'], subject.reverse) }
272
+ it('#reverse_each') { assert_equal([subject[3], subject[2], subject[1], 'foo'], subject.reverse_each.to_a) }
273
+ it('#rindex') { assert_equal(0, subject.rindex('foo')) }
274
+ it('#rotate') { assert_equal([subject[1], subject[2], subject[3], 'foo'], subject.rotate) }
275
+ it('#sample') { assert_equal('a', schema.new_jsi(['a']).sample) }
276
+ it('#shelljoin') { assert_equal('a', schema.new_jsi(['a']).shelljoin) } if [].respond_to?(:shelljoin)
277
+ it('#shuffle') { assert_equal(4, subject.shuffle.size) }
278
+ it('#slice') { assert_equal(['foo'], subject.slice(0, 1)) }
279
+ it('#sort') { assert_equal(['a'], schema.new_jsi(['a']).sort) }
280
+ it('#take') { assert_equal(['foo'], subject.take(1)) }
281
+ it('#take_while') { assert_equal([], subject.take_while { false }) }
282
+ it('#transpose') { assert_equal([], schema.new_jsi([]).transpose) }
283
+ it('#uniq') { assert_equal(subject.to_a, subject.uniq) }
284
+ it('#values_at') { assert_equal(['foo'], subject.values_at(0)) }
285
+ it('#zip') { assert_equal([['foo', 'foo'], [subject[1], subject[1]], [subject[2], subject[2]], [subject[3], subject[3]]], subject.zip(subject)) }
286
+ end
287
+ describe 'with an instance that has to_ary but not other ary instance methods' do
288
+ let(:instance) { SortOfArray.new(['foo', {'lamp' => SortOfArray.new([3])}, SortOfArray.new(['q', 'r'])]) }
289
+ describe 'delegating instance methods to #to_ary' do
290
+ it('#each_index') { assert_equal([0, 1, 2], subject.each_index.to_a) }
291
+ it('#size') { assert_equal(3, subject.size) }
292
+ it('#count') { assert_equal(1, subject.count('foo')) }
293
+ it('#slice') { assert_equal(['foo'], subject.slice(0, 1)) }
294
+ it('#[]') { assert_equal(SortOfArray.new(['q', 'r']), subject[2].jsi_instance) }
295
+ it('#as_json') { assert_equal(['foo', {'lamp' => [3]}, ['q', 'r']], subject.as_json) }
296
+ end
168
297
  end
169
298
  describe 'modified copy methods' do
170
- it('#reject') { assert_equal(class_for_schema.new(JSI::JSON::ArrayNode.new(['foo'], [])), subject.reject { |e| e != 'foo' }) }
299
+ it('#reject') { assert_equal(schema.new_jsi(['foo']), subject.reject { |e| e != 'foo' }) }
171
300
  it('#reject block var') do
172
301
  subj_a = subject.to_a
173
302
  subject.reject { |e| assert_equal(e, subj_a.shift) }
174
303
  end
175
- it('#select') { assert_equal(class_for_schema.new(JSI::JSON::ArrayNode.new(['foo'], [])), subject.select { |e| e == 'foo' }) }
304
+ it('#select') { assert_equal(schema.new_jsi(['foo']), subject.select { |e| e == 'foo' }) }
176
305
  it('#select block var') do
177
306
  subj_a = subject.to_a
178
307
  subject.select { |e| assert_equal(e, subj_a.shift) }
179
308
  end
180
309
  it('#compact') { assert_equal(subject, subject.compact) }
181
310
  describe 'at a depth' do
182
- let(:document) { [['b', 'q'], {'c' => ['d', 'e']}] }
183
- let(:path) { ['1', 'c'] }
184
311
  it('#select') do
185
- selected = subject.select { |e| e == 'd' }
186
- equivalent_node = JSI::JSON::ArrayNode.new([['b', 'q'], {'c' => ['d']}], path)
187
- equivalent = class_for_schema.new(equivalent_node)
188
- assert_equal(equivalent, selected)
312
+ expected = schema.new_jsi(['foo', {'lamp' => [3]}, ['r'], {'four' => 4}])[2]
313
+ actual = subject[2].select { |e| e == 'r' }
314
+ assert_equal(expected, actual)
189
315
  end
190
316
  end
191
317
  end
@@ -1,13 +1,21 @@
1
1
  require_relative 'test_helper'
2
2
 
3
- describe JSI::BaseHash do
4
- let(:document) do
5
- {'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => true}
6
- end
7
- let(:path) { [] }
8
- let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
3
+ base = {
4
+ 'description' => 'named hash schema',
5
+ 'type' => 'object',
6
+ 'properties' => {
7
+ 'foo' => {'type' => 'object'},
8
+ 'bar' => {},
9
+ },
10
+ }
11
+ NamedHashInstance = JSI::Schema.new(base).jsi_schema_class
12
+ NamedIdHashInstance = JSI::Schema.new({'$id' => 'https://schemas.jsi.unth.net/test/base/named_hash_schema'}.merge(base)).jsi_schema_class
13
+
14
+ describe 'JSI::Base hash' do
15
+ let(:instance) { {'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => [true]} }
9
16
  let(:schema_content) do
10
17
  {
18
+ 'description' => 'hash schema',
11
19
  'type' => 'object',
12
20
  'properties' => {
13
21
  'foo' => {'type' => 'object'},
@@ -16,10 +24,9 @@ describe JSI::BaseHash do
16
24
  }
17
25
  end
18
26
  let(:schema) { JSI::Schema.new(schema_content) }
19
- let(:class_for_schema) { JSI.class_for_schema(schema) }
20
- let(:subject) { class_for_schema.new(instance) }
27
+ let(:subject) { schema.new_jsi(instance) }
21
28
 
22
- describe '#[] with a default that is a basic type' do
29
+ describe '#[] with a schema default that is a basic type' do
23
30
  let(:schema_content) do
24
31
  {
25
32
  'type' => 'object',
@@ -29,26 +36,26 @@ describe JSI::BaseHash do
29
36
  }
30
37
  end
31
38
  describe 'default value' do
32
- let(:document) { {'bar' => 3} }
39
+ let(:instance) { {'bar' => 3} }
33
40
  it 'returns the default value' do
34
41
  assert_equal('foo', subject.foo)
35
42
  end
36
43
  end
37
44
  describe 'nondefault value (basic type)' do
38
- let(:document) { {'foo' => 'who'} }
45
+ let(:instance) { {'foo' => 'who'} }
39
46
  it 'returns the nondefault value' do
40
47
  assert_equal('who', subject.foo)
41
48
  end
42
49
  end
43
50
  describe 'nondefault value (nonbasic type)' do
44
- let(:document) { {'foo' => [2]} }
51
+ let(:instance) { {'foo' => [2]} }
45
52
  it 'returns the nondefault value' do
46
- assert_instance_of(JSI.class_for_schema(schema['properties']['foo']), subject.foo)
53
+ assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
47
54
  assert_equal([2], subject.foo.as_json)
48
55
  end
49
56
  end
50
57
  end
51
- describe '#[] with a default that is a nonbasic type' do
58
+ describe '#[] with a schema default that is a nonbasic type' do
52
59
  let(:schema_content) do
53
60
  {
54
61
  'type' => 'object',
@@ -58,26 +65,43 @@ describe JSI::BaseHash do
58
65
  }
59
66
  end
60
67
  describe 'default value' do
61
- let(:document) { {'bar' => 3} }
68
+ let(:instance) { {'bar' => 3} }
62
69
  it 'returns the default value' do
63
- assert_instance_of(JSI.class_for_schema(schema['properties']['foo']), subject.foo)
70
+ assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
64
71
  assert_equal({'foo' => 2}, subject.foo.as_json)
65
72
  end
66
73
  end
67
74
  describe 'nondefault value (basic type)' do
68
- let(:document) { {'foo' => 'who'} }
75
+ let(:instance) { {'foo' => 'who'} }
69
76
  it 'returns the nondefault value' do
70
77
  assert_equal('who', subject.foo)
71
78
  end
72
79
  end
73
80
  describe 'nondefault value (nonbasic type)' do
74
- let(:document) { {'foo' => [2]} }
81
+ let(:instance) { {'foo' => [2]} }
75
82
  it 'returns the nondefault value' do
76
- assert_instance_of(JSI.class_for_schema(schema['properties']['foo']), subject.foo)
83
+ assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
77
84
  assert_equal([2], subject.foo.as_json)
78
85
  end
79
86
  end
80
87
  end
88
+ describe '#[] with a hash default that is a nonbasic type' do
89
+ let(:schema_content) do
90
+ {
91
+ 'type' => 'object',
92
+ 'properties' => {
93
+ 'foo' => {},
94
+ },
95
+ }
96
+ end
97
+ describe 'default value' do
98
+ let(:instance) { Hash.new({'foo' => 2}).merge({'bar' => 3}) }
99
+ it 'returns the default value' do
100
+ assert_is_a(Hash, subject.foo)
101
+ assert_equal({'foo' => 2}, subject.foo)
102
+ end
103
+ end
104
+ end
81
105
  describe 'hashlike []=' do
82
106
  it 'sets a property' do
83
107
  orig_foo = subject['foo']
@@ -85,8 +109,8 @@ describe JSI::BaseHash do
85
109
  subject['foo'] = {'y' => 'z'}
86
110
 
87
111
  assert_equal({'y' => 'z'}, subject['foo'].as_json)
88
- assert_instance_of(JSI.class_for_schema(schema.schema_node['properties']['foo']), orig_foo)
89
- assert_instance_of(JSI.class_for_schema(schema.schema_node['properties']['foo']), subject['foo'])
112
+ assert_is_a(schema.properties['foo'].jsi_schema_module, orig_foo)
113
+ assert_is_a(schema.properties['foo'].jsi_schema_module, subject['foo'])
90
114
  end
91
115
  it 'sets a property to a schema instance with a different schema' do
92
116
  assert(subject['foo'])
@@ -96,11 +120,11 @@ describe JSI::BaseHash do
96
120
  # the content of the subscripts' instances is the same but the subscripts' classes are different
97
121
  assert_equal([9], subject['foo'].as_json)
98
122
  assert_equal([9], subject['bar'].as_json)
99
- assert_instance_of(JSI.class_for_schema(schema.schema_node['properties']['foo']), subject['foo'])
100
- assert_instance_of(JSI.class_for_schema(schema.schema_node['properties']['bar']), subject['bar'])
123
+ assert_is_a(schema.properties['foo'].jsi_schema_module, subject['foo'])
124
+ assert_is_a(schema.properties['bar'].jsi_schema_module, subject['bar'])
101
125
  end
102
126
  it 'sets a property to a schema instance with the same schema' do
103
- other_subject = class_for_schema.new(JSI::JSON::Node.new_doc({'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => true}))
127
+ other_subject = schema.new_jsi({'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => [true]})
104
128
  # Given
105
129
  assert_equal(other_subject, subject)
106
130
 
@@ -114,20 +138,130 @@ describe JSI::BaseHash do
114
138
  refute_equal(other_subject['foo'].object_id, subject['foo'].object_id)
115
139
  end
116
140
  it 'modifies the instance, visible to other references to the same instance' do
117
- orig_instance = subject.instance
141
+ orig_instance = subject.jsi_instance
118
142
 
119
143
  subject['foo'] = {'y' => 'z'}
120
144
 
121
- assert_equal(orig_instance, subject.instance)
122
- assert_equal({'y' => 'z'}, orig_instance['foo'].as_json)
123
- assert_equal({'y' => 'z'}, subject.instance['foo'].as_json)
124
- assert_equal(orig_instance.class, subject.instance.class)
145
+ assert_equal(orig_instance, subject.jsi_instance)
146
+ assert_equal({'y' => 'z'}, orig_instance['foo'])
147
+ assert_equal({'y' => 'z'}, subject.jsi_instance['foo'])
148
+ assert_equal(orig_instance.class, subject.jsi_instance.class)
125
149
  end
126
150
  describe 'when the instance is not hashlike' do
127
151
  let(:instance) { nil }
128
152
  it 'errors' do
129
153
  err = assert_raises(NoMethodError) { subject['foo'] = 0 }
130
- assert_match(%r(\Aundefined method `\[\]=' for #<JSI::SchemaClasses::.*>\z), err.message)
154
+ assert_equal('cannot assign subcript (using token: "foo") to instance: nil', err.message)
155
+ end
156
+ end
157
+ describe '#inspect' do
158
+ it 'inspects' do
159
+ assert_equal("\#{<JSI> \"foo\" => \#{<JSI> \"x\" => \"y\"}, \"bar\" => #[<JSI> 9], \"baz\" => [true]}", subject.inspect)
160
+ end
161
+ end
162
+ describe '#pretty_print' do
163
+ it 'pretty_prints' do
164
+ assert_equal("\#{<JSI> \"foo\" => \#{<JSI> \"x\" => \"y\"}, \"bar\" => #[<JSI> 9], \"baz\" => [true]}\n", subject.pretty_inspect)
165
+ end
166
+ end
167
+ describe '#inspect SortOfHash' do
168
+ let(:subject) { schema.new_jsi(SortOfHash.new(instance)) }
169
+ it 'inspects' do
170
+ assert_equal("\#{<JSI SortOfHash> \"foo\" => \#{<JSI> \"x\" => \"y\"}, \"bar\" => #[<JSI> 9], \"baz\" => [true]}", subject.inspect)
171
+ end
172
+ end
173
+ describe '#pretty_print SortOfHash' do
174
+ let(:subject) { schema.new_jsi(SortOfHash.new(instance)) }
175
+ it 'pretty_prints' do
176
+ assert_equal("\#{<JSI SortOfHash>\n \"foo\" => \#{<JSI> \"x\" => \"y\"},\n \"bar\" => #[<JSI> 9],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
177
+ end
178
+ end
179
+ describe '#inspect named' do
180
+ let(:subject) { NamedHashInstance.new(instance) }
181
+ it 'inspects' do
182
+ assert_equal("\#{<NamedHashInstance> \"foo\" => \#{<JSI> \"x\" => \"y\"}, \"bar\" => #[<JSI> 9], \"baz\" => [true]}", subject.inspect)
183
+ end
184
+ end
185
+ describe '#pretty_print named' do
186
+ let(:subject) { NamedHashInstance.new(instance) }
187
+ it 'inspects' do
188
+ assert_equal("\#{<NamedHashInstance>\n \"foo\" => \#{<JSI> \"x\" => \"y\"},\n \"bar\" => #[<JSI> 9],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
189
+ end
190
+ end
191
+ describe '#inspect named SortOfHash' do
192
+ let(:subject) { NamedHashInstance.new(SortOfHash.new(instance)) }
193
+ it 'inspects' do
194
+ assert_equal("\#{<NamedHashInstance SortOfHash> \"foo\" => \#{<JSI> \"x\" => \"y\"}, \"bar\" => #[<JSI> 9], \"baz\" => [true]}", subject.inspect)
195
+ end
196
+ end
197
+ describe '#pretty_print named SortOfHash' do
198
+ let(:subject) { NamedHashInstance.new(SortOfHash.new(instance)) }
199
+ it 'inspects' do
200
+ assert_equal("\#{<NamedHashInstance SortOfHash>\n \"foo\" => \#{<JSI> \"x\" => \"y\"},\n \"bar\" => #[<JSI> 9],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
201
+ end
202
+ end
203
+ describe '#inspect named with id' do
204
+ let(:subject) { NamedIdHashInstance.new(instance) }
205
+ it 'inspects' do
206
+ assert_equal("\#{<NamedIdHashInstance> \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/foo)> \"x\" => \"y\"}, \"bar\" => #[<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/bar)> 9], \"baz\" => [true]}", subject.inspect)
207
+ end
208
+ end
209
+ describe '#pretty_print named with id' do
210
+ let(:subject) { NamedIdHashInstance.new(instance) }
211
+ it 'inspects' do
212
+ assert_equal("\#{<NamedIdHashInstance>\n \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/foo)>\n \"x\" => \"y\"\n },\n \"bar\" => #[<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/bar)>\n 9\n ],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
213
+ end
214
+ end
215
+ describe '#inspect named SortOfHash with id' do
216
+ let(:subject) { NamedIdHashInstance.new(SortOfHash.new(instance)) }
217
+ it 'inspects' do
218
+ assert_equal("\#{<NamedIdHashInstance SortOfHash> \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/foo)> \"x\" => \"y\"}, \"bar\" => #[<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/bar)> 9], \"baz\" => [true]}", subject.inspect)
219
+ end
220
+ end
221
+ describe '#pretty_print named with id SortOfHash' do
222
+ let(:subject) { NamedIdHashInstance.new(SortOfHash.new(instance)) }
223
+ it 'inspects' do
224
+ assert_equal("\#{<NamedIdHashInstance SortOfHash>\n \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/foo)>\n \"x\" => \"y\"\n },\n \"bar\" => #[<JSI (https://schemas.jsi.unth.net/test/base/named_hash_schema#/properties/bar)>\n 9\n ],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
225
+ end
226
+ end
227
+ describe '#inspect with id' do
228
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_hash_test/withid', 'properties' => {'foo' => {}, 'bar' => {}}} }
229
+ let(:subject) { schema.new_jsi(instance) }
230
+ it 'inspects' do
231
+ assert_equal("\#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#)> \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/foo)> \"x\" => \"y\"}, \"bar\" => #[<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/bar)> 9], \"baz\" => [true]}", subject.inspect)
232
+ end
233
+ end
234
+ describe '#pretty_print with id' do
235
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_hash_test/withid', 'properties' => {'foo' => {}, 'bar' => {}}} }
236
+ let(:subject) { schema.new_jsi(instance) }
237
+ it 'inspects' do
238
+ assert_equal("\#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#)>\n \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/foo)>\n \"x\" => \"y\"\n },\n \"bar\" => #[<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/bar)>\n 9\n ],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
239
+ end
240
+ end
241
+ describe '#inspect with id SortOfHash' do
242
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_hash_test/withid', 'properties' => {'foo' => {}, 'bar' => {}}} }
243
+ let(:subject) { schema.new_jsi(SortOfHash.new(instance)) }
244
+ it 'inspects' do
245
+ assert_equal("\#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#) SortOfHash> \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/foo)> \"x\" => \"y\"}, \"bar\" => #[<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/bar)> 9], \"baz\" => [true]}", subject.inspect)
246
+ end
247
+ end
248
+ describe '#pretty_print with id SortOfHash' do
249
+ let(:schema_content) { {'$id' => 'https://schemas.jsi.unth.net/base_hash_test/withid', 'properties' => {'foo' => {}, 'bar' => {}}} }
250
+ let(:subject) { schema.new_jsi(SortOfHash.new(instance)) }
251
+ it 'inspects' do
252
+ assert_equal("\#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#) SortOfHash>\n \"foo\" => \#{<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/foo)>\n \"x\" => \"y\"\n },\n \"bar\" => #[<JSI (https://schemas.jsi.unth.net/base_hash_test/withid#/properties/bar)>\n 9\n ],\n \"baz\" => [true]\n}\n", subject.pretty_inspect)
253
+ end
254
+ end
255
+ describe '#inspect Node' do
256
+ let(:subject) { schema.new_jsi(JSI::JSON::Node.new_doc(instance)) }
257
+ it 'inspects' do
258
+ assert_equal("\#{<JSI JSI::JSON::HashNode #> \"foo\" => \#{<JSI JSI::JSON::HashNode #/foo> \"x\" => \"y\"}, \"bar\" => #[<JSI JSI::JSON::ArrayNode #/bar> 9], \"baz\" => #[<JSI::JSON::ArrayNode #/baz> true]}", subject.inspect)
259
+ end
260
+ end
261
+ describe '#pretty_print Node' do
262
+ let(:subject) { schema.new_jsi(JSI::JSON::Node.new_doc(instance)) }
263
+ it 'pretty_prints' do
264
+ assert_equal("\#{<JSI JSI::JSON::HashNode #>\n \"foo\" => \#{<JSI JSI::JSON::HashNode #/foo> \"x\" => \"y\"},\n \"bar\" => #[<JSI JSI::JSON::ArrayNode #/bar> 9],\n \"baz\" => #[<JSI::JSON::ArrayNode #/baz> true]\n}\n", subject.pretty_inspect)
131
265
  end
132
266
  end
133
267
  end
@@ -137,43 +271,52 @@ describe JSI::BaseHash do
137
271
  it('#empty?') { assert_equal(false, subject.empty?) }
138
272
  it('#has_key?') { assert_equal(true, subject.has_key?('bar')) }
139
273
  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) }
274
+ it('#key?') { assert_equal(true, subject.key?('baz')) }
275
+ it('#keys') { assert_equal(['foo', 'bar', 'baz'], subject.keys) }
276
+ it('#length') { assert_equal(3, subject.length) }
277
+ it('#member?') { assert_equal(false, subject.member?(0)) }
278
+ it('#size') { assert_equal(3, subject.size) }
145
279
  end
146
280
  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')) }
157
- 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)
281
+ it('#<') { assert_equal(true, subject < {'foo' => subject['foo'], 'bar' => subject['bar'], 'baz' => subject['baz'], 'x' => 'y'}) } if {}.respond_to?(:<)
282
+ it('#<=') { assert_equal(true, subject <= subject) } if {}.respond_to?(:<=)
283
+ it('#>') { assert_equal(true, subject > {}) } if {}.respond_to?(:>)
284
+ it('#>=') { assert_equal(false, subject >= {'foo' => 'bar'}) } if {}.respond_to?(:>=)
285
+ it('#any?') { assert_equal(false, subject.any? { |k, v| v == 3 }) }
286
+ it('#assoc') { assert_equal(['foo', subject['foo']], subject.assoc('foo')) }
287
+ it('#dig') { assert_equal(9, subject.dig('bar', 0)) } if {}.respond_to?(:dig)
288
+ it('#each_pair') { assert_equal([['foo', subject['foo']], ['bar', subject['bar']], ['baz', [true]]], subject.each_pair.to_a) }
289
+ it('#each_value') { assert_equal([subject['foo'], subject['bar'], [true]], subject.each_value.to_a) }
290
+ it('#fetch') { assert_equal([true], subject.fetch('baz')) }
291
+ it('#fetch_values') { assert_equal([[true]], subject.fetch_values('baz')) } if {}.respond_to?(:fetch_values)
292
+ it('#has_value?') { assert_equal(true, subject.has_value?([true])) }
293
+ it('#invert') { assert_equal({subject['foo'] => 'foo', subject['bar'] => 'bar', [true] => 'baz'}, subject.invert) }
294
+ it('#key') { assert_equal('baz', subject.key([true])) }
295
+ it('#rassoc') { assert_equal(['baz', [true]], subject.rassoc([true])) }
296
+ it('#to_h') { assert_equal({'foo' => subject['foo'], 'bar' => subject['bar'], 'baz' => [true]}, subject.to_h) }
297
+ it('#to_proc') { assert_equal([true], subject.to_proc.call('baz')) } if {}.respond_to?(:to_proc)
164
298
  if {}.respond_to?(:transform_values)
165
299
  it('#transform_values') { assert_equal({'foo' => nil, 'bar' => nil, 'baz' => nil}, subject.transform_values { |_| nil }) }
166
300
  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')) }
301
+ it('#value?') { assert_equal(false, subject.value?('0')) }
302
+ it('#values') { assert_equal([subject['foo'], subject['bar'], [true]], subject.values) }
303
+ it('#values_at') { assert_equal([[true]], subject.values_at('baz')) }
304
+ end
305
+ describe 'with an instance that has to_hash but not other hash instance methods' do
306
+ let(:instance) { SortOfHash.new({'foo' => SortOfHash.new({'a' => 'b'})}) }
307
+ describe 'delegating instance methods to #to_hash' do
308
+ it('#each_key') { assert_equal(['foo'], subject.each_key.to_a) }
309
+ it('#each_pair') { assert_equal([['foo', subject['foo']]], subject.each_pair.to_a) }
310
+ it('#[]') { assert_equal(SortOfHash.new({'a' => 'b'}), subject['foo'].jsi_instance) }
311
+ it('#as_json') { assert_equal({'foo' => {'a' => 'b'}}, subject.as_json) }
312
+ end
170
313
  end
171
314
  describe 'modified copy methods' do
172
315
  # I'm going to rely on the #merge test above to test the modified copy functionality and just do basic
173
316
  # 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 }) }
317
+ it('#merge') { assert_equal(subject, subject.merge({})) }
318
+ it('#reject') { assert_equal(schema.new_jsi({}), subject.reject { true }) }
319
+ it('#select') { assert_equal(schema.new_jsi({}), subject.select { false }) }
177
320
  describe '#select' do
178
321
  it 'yields properly too' do
179
322
  subject.select do |k, v|