jsi 0.4.0 → 0.7.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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +33 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +114 -42
  6. data/jsi.gemspec +14 -12
  7. data/lib/jsi/base/node.rb +183 -0
  8. data/lib/jsi/base.rb +388 -220
  9. data/lib/jsi/jsi_coder.rb +8 -7
  10. data/lib/jsi/metaschema.rb +0 -1
  11. data/lib/jsi/metaschema_node/bootstrap_schema.rb +101 -0
  12. data/lib/jsi/metaschema_node.rb +159 -135
  13. data/lib/jsi/ptr.rb +303 -0
  14. data/lib/jsi/schema/application/child_application/contains.rb +25 -0
  15. data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
  16. data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
  17. data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
  18. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  19. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  20. data/lib/jsi/schema/application/child_application.rb +38 -0
  21. data/lib/jsi/schema/application/draft04.rb +8 -0
  22. data/lib/jsi/schema/application/draft06.rb +8 -0
  23. data/lib/jsi/schema/application/draft07.rb +8 -0
  24. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  25. data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
  26. data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
  27. data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
  28. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  29. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  30. data/lib/jsi/schema/application/inplace_application/someof.rb +44 -0
  31. data/lib/jsi/schema/application/inplace_application.rb +41 -0
  32. data/lib/jsi/schema/application.rb +12 -0
  33. data/lib/jsi/schema/draft04.rb +14 -0
  34. data/lib/jsi/schema/draft06.rb +14 -0
  35. data/lib/jsi/schema/draft07.rb +14 -0
  36. data/lib/jsi/schema/issue.rb +36 -0
  37. data/lib/jsi/schema/ref.rb +160 -0
  38. data/lib/jsi/schema/schema_ancestor_node.rb +113 -0
  39. data/lib/jsi/schema/validation/array.rb +69 -0
  40. data/lib/jsi/schema/validation/const.rb +20 -0
  41. data/lib/jsi/schema/validation/contains.rb +25 -0
  42. data/lib/jsi/schema/validation/core.rb +39 -0
  43. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  44. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  45. data/lib/jsi/schema/validation/draft04.rb +112 -0
  46. data/lib/jsi/schema/validation/draft06.rb +122 -0
  47. data/lib/jsi/schema/validation/draft07.rb +159 -0
  48. data/lib/jsi/schema/validation/enum.rb +25 -0
  49. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  50. data/lib/jsi/schema/validation/items.rb +54 -0
  51. data/lib/jsi/schema/validation/not.rb +20 -0
  52. data/lib/jsi/schema/validation/numeric.rb +121 -0
  53. data/lib/jsi/schema/validation/object.rb +45 -0
  54. data/lib/jsi/schema/validation/pattern.rb +34 -0
  55. data/lib/jsi/schema/validation/properties.rb +101 -0
  56. data/lib/jsi/schema/validation/property_names.rb +32 -0
  57. data/lib/jsi/schema/validation/ref.rb +40 -0
  58. data/lib/jsi/schema/validation/required.rb +27 -0
  59. data/lib/jsi/schema/validation/someof.rb +90 -0
  60. data/lib/jsi/schema/validation/string.rb +47 -0
  61. data/lib/jsi/schema/validation/type.rb +49 -0
  62. data/lib/jsi/schema/validation.rb +51 -0
  63. data/lib/jsi/schema.rb +508 -149
  64. data/lib/jsi/schema_classes.rb +199 -59
  65. data/lib/jsi/schema_registry.rb +151 -0
  66. data/lib/jsi/schema_set.rb +181 -0
  67. data/lib/jsi/simple_wrap.rb +23 -4
  68. data/lib/jsi/util/private/attr_struct.rb +127 -0
  69. data/lib/jsi/util/private.rb +204 -0
  70. data/lib/jsi/util/typelike.rb +229 -0
  71. data/lib/jsi/util.rb +89 -53
  72. data/lib/jsi/validation/error.rb +34 -0
  73. data/lib/jsi/validation/result.rb +210 -0
  74. data/lib/jsi/validation.rb +15 -0
  75. data/lib/jsi/version.rb +3 -1
  76. data/lib/jsi.rb +44 -14
  77. data/lib/schemas/json-schema.org/draft-04/schema.rb +10 -3
  78. data/lib/schemas/json-schema.org/draft-06/schema.rb +10 -3
  79. data/lib/schemas/json-schema.org/draft-07/schema.rb +14 -0
  80. data/readme.rb +138 -0
  81. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  82. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  83. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  84. metadata +75 -122
  85. data/.simplecov +0 -3
  86. data/Rakefile.rb +0 -9
  87. data/lib/jsi/base/to_rb.rb +0 -128
  88. data/lib/jsi/json/node.rb +0 -203
  89. data/lib/jsi/json/pointer.rb +0 -419
  90. data/lib/jsi/json-schema-fragments.rb +0 -61
  91. data/lib/jsi/json.rb +0 -10
  92. data/lib/jsi/pathed_node.rb +0 -118
  93. data/lib/jsi/typelike_modules.rb +0 -240
  94. data/resources/icons/AGPL-3.0.png +0 -0
  95. data/test/base_array_test.rb +0 -323
  96. data/test/base_hash_test.rb +0 -337
  97. data/test/base_test.rb +0 -486
  98. data/test/jsi_coder_test.rb +0 -85
  99. data/test/jsi_json_arraynode_test.rb +0 -150
  100. data/test/jsi_json_hashnode_test.rb +0 -132
  101. data/test/jsi_json_node_test.rb +0 -257
  102. data/test/jsi_json_pointer_test.rb +0 -102
  103. data/test/jsi_test.rb +0 -11
  104. data/test/jsi_typelike_as_json_test.rb +0 -53
  105. data/test/metaschema_node_test.rb +0 -19
  106. data/test/schema_module_test.rb +0 -21
  107. data/test/schema_test.rb +0 -208
  108. data/test/spreedly_openapi_test.rb +0 -8
  109. data/test/test_helper.rb +0 -97
  110. data/test/util_test.rb +0 -62
@@ -1,240 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JSI
4
- # a module relating to objects that act like Hash or Array instances
5
- module Typelike
6
- # yields the content of the given param `object`. for objects which have a
7
- # #modified_copy method of their own (JSI::Base, JSI::JSON::Node) that
8
- # method is invoked with the given block. otherwise the given object itself
9
- # is yielded.
10
- #
11
- # the given block must result in a modified copy of its block parameter
12
- # (not destructively modifying the yielded content).
13
- #
14
- # @yield [Object] the content of the given object. the block should result
15
- # in a (nondestructively) modified copy of this.
16
- # @return [object.class] modified copy of the given object
17
- def self.modified_copy(object, &block)
18
- if object.respond_to?(:modified_copy)
19
- object.modified_copy(&block)
20
- else
21
- return yield(object)
22
- end
23
- end
24
-
25
- # recursive method to express the given argument object in json-compatible
26
- # types of Hash, Array, and basic types of String/boolean/numeric/nil. this
27
- # will raise TypeError if an object is given that is not a type that seems
28
- # to be expressable as json.
29
- #
30
- # similar effect could be achieved by requiring 'json/add/core' and using
31
- # #as_json, but I don't much care for how it represents classes that are
32
- # not naturally expressable in JSON, and prefer not to load its
33
- # monkey-patching.
34
- #
35
- # @param object [Object] the object to be converted to jsonifiability
36
- # @return [Array, Hash, String, Boolean, NilClass, Numeric] jsonifiable
37
- # expression of param object
38
- # @raise [TypeError] when the object (or an object nested with a hash or
39
- # array of object) cannot be expressed as json
40
- def self.as_json(object, *opt)
41
- if object.is_a?(JSI::PathedNode)
42
- as_json(object.node_content, *opt)
43
- elsif object.respond_to?(:to_hash)
44
- (object.respond_to?(:map) ? object : object.to_hash).map do |k, v|
45
- unless k.is_a?(Symbol) || k.respond_to?(:to_str)
46
- raise(TypeError, "json object (hash) cannot be keyed with: #{k.pretty_inspect.chomp}")
47
- end
48
- {k.to_s => as_json(v, *opt)}
49
- end.inject({}, &:update)
50
- elsif object.respond_to?(:to_ary)
51
- (object.respond_to?(:map) ? object : object.to_ary).map { |e| as_json(e, *opt) }
52
- elsif [String, TrueClass, FalseClass, NilClass, Numeric].any? { |c| object.is_a?(c) }
53
- object
54
- elsif object.is_a?(Symbol)
55
- object.to_s
56
- elsif object.is_a?(Set)
57
- as_json(object.to_a, *opt)
58
- elsif object.respond_to?(:as_json)
59
- as_json(object.as_json(*opt), *opt)
60
- else
61
- raise(TypeError, "cannot express object as json: #{object.pretty_inspect.chomp}")
62
- end
63
- end
64
- end
65
-
66
- # a module of methods for objects which behave like Hash but are not Hash.
67
- #
68
- # this module is intended to be internal to JSI. no guarantees or API promises
69
- # are made for non-JSI classes including this module.
70
- module Hashlike
71
- # safe methods which can be delegated to #to_hash (which the includer is assumed to have defined).
72
- # 'safe' means, in this context, nondestructive - methods which do not modify the receiver.
73
-
74
- # methods which do not need to access the value.
75
- SAFE_KEY_ONLY_METHODS = %w(each_key empty? has_key? include? key? keys length member? size)
76
- SAFE_KEY_VALUE_METHODS = %w(< <= > >= any? assoc compact dig each_pair each_value fetch fetch_values has_value? invert key merge rassoc reject select to_h to_proc transform_values value? values values_at)
77
- DESTRUCTIVE_METHODS = %w(clear delete delete_if keep_if reject! replace select! shift)
78
- # these return a modified copy
79
- safe_modified_copy_methods = %w(compact)
80
- # select and reject will return a modified copy but need the yielded block variable value from #[]
81
- safe_kv_block_modified_copy_methods = %w(select reject)
82
- SAFE_METHODS = SAFE_KEY_ONLY_METHODS | SAFE_KEY_VALUE_METHODS
83
- safe_to_hash_methods = SAFE_METHODS - safe_modified_copy_methods - safe_kv_block_modified_copy_methods
84
- safe_to_hash_methods.each do |method_name|
85
- define_method(method_name) { |*a, &b| to_hash.public_send(method_name, *a, &b) }
86
- end
87
- safe_modified_copy_methods.each do |method_name|
88
- define_method(method_name) do |*a, &b|
89
- modified_copy do |object_to_modify|
90
- responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_hash
91
- responsive_object.public_send(method_name, *a, &b)
92
- end
93
- end
94
- end
95
- safe_kv_block_modified_copy_methods.each do |method_name|
96
- define_method(method_name) do |*a, &b|
97
- modified_copy do |object_to_modify|
98
- responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_hash
99
- responsive_object.public_send(method_name, *a) do |k, _v|
100
- b.call(k, self[k])
101
- end
102
- end
103
- end
104
- end
105
-
106
- # the same as Hash#update
107
- # @param other [#to_hash] the other hash to update this hash from
108
- # @yield [key, oldval, newval] for entries with duplicate keys, the value of each duplicate key
109
- # is determined by calling the block with the key, its value in hsh and its value in other_hash.
110
- # @return self, updated with other
111
- # @raise [TypeError] when `other` does not respond to #to_hash
112
- def update(other, &block)
113
- unless other.respond_to?(:to_hash)
114
- raise(TypeError, "cannot update with argument that does not respond to #to_hash: #{other.pretty_inspect.chomp}")
115
- end
116
- self_respondingto_key = self.respond_to?(:key?) ? self : to_hash
117
- other.to_hash.each_pair do |key, value|
118
- if block_given? && self_respondingto_key.key?(key)
119
- value = yield(key, self[key], value)
120
- end
121
- self[key] = value
122
- end
123
- self
124
- end
125
-
126
- alias_method :merge!, :update
127
-
128
- # the same as Hash#merge
129
- # @param other [#to_hash] the other hash to merge into this
130
- # @yield [key, oldval, newval] for entries with duplicate keys, the value of each duplicate key
131
- # is determined by calling the block with the key, its value in hsh and its value in other_hash.
132
- # @return duplicate of this hash with the other hash merged in
133
- # @raise [TypeError] when `other` does not respond to #to_hash
134
- def merge(other, &block)
135
- dup.update(other, &block)
136
- end
137
-
138
- # @return [String] basically the same #inspect as Hash, but has the
139
- # class name and, if responsive, self's #object_group_text
140
- def inspect
141
- object_group_str = (respond_to?(:object_group_text) ? self.object_group_text : [self.class]).join(' ')
142
- "\#{<#{object_group_str}>#{empty? ? '' : ' '}#{self.map { |k, v| "#{k.inspect} => #{v.inspect}" }.join(', ')}}"
143
- end
144
-
145
- alias_method :to_s, :inspect
146
-
147
- # pretty-prints a representation this node to the given printer
148
- # @return [void]
149
- def pretty_print(q)
150
- object_group_str = (respond_to?(:object_group_text) ? object_group_text : [self.class]).join(' ')
151
- q.text "\#{<#{object_group_str}>"
152
- q.group_sub {
153
- q.nest(2) {
154
- q.breakable(any? { true } ? ' ' : '')
155
- q.seplist(self, nil, :each_pair) { |k, v|
156
- q.group {
157
- q.pp k
158
- q.text ' => '
159
- q.pp v
160
- }
161
- }
162
- }
163
- }
164
- q.breakable ''
165
- q.text '}'
166
- end
167
- end
168
-
169
- # a module of methods for objects which behave like Array but are not Array.
170
- #
171
- # this module is intended to be internal to JSI. no guarantees or API promises
172
- # are made for non-JSI classes including this module.
173
- module Arraylike
174
- # safe methods which can be delegated to #to_ary (which the includer is assumed to have defined).
175
- # 'safe' means, in this context, nondestructive - methods which do not modify the receiver.
176
-
177
- # methods which do not need to access the element.
178
- SAFE_INDEX_ONLY_METHODS = %w(each_index empty? length size)
179
- # there are some ambiguous ones that are omitted, like #sort, #map / #collect.
180
- SAFE_INDEX_ELEMENT_METHODS = %w(| & * + - <=> abbrev assoc at bsearch bsearch_index combination compact count cycle dig drop drop_while fetch find_index first include? index join last pack permutation product reject repeated_combination repeated_permutation reverse reverse_each rindex rotate sample select shelljoin shuffle slice sort take take_while transpose uniq values_at zip)
181
- DESTRUCTIVE_METHODS = %w(<< clear collect! compact! concat delete delete_at delete_if fill flatten! insert keep_if map! pop push reject! replace reverse! rotate! select! shift shuffle! slice! sort! sort_by! uniq! unshift)
182
-
183
- # methods (well, method) that returns a modified copy and doesn't need any handling of block variable(s)
184
- safe_modified_copy_methods = %w(compact)
185
-
186
- # methods that return a modified copy and do need handling of block variables
187
- safe_el_block_methods = %w(reject select)
188
-
189
- SAFE_METHODS = SAFE_INDEX_ONLY_METHODS | SAFE_INDEX_ELEMENT_METHODS
190
- safe_to_ary_methods = SAFE_METHODS - safe_modified_copy_methods - safe_el_block_methods
191
- safe_to_ary_methods.each do |method_name|
192
- define_method(method_name) { |*a, &b| to_ary.public_send(method_name, *a, &b) }
193
- end
194
- safe_modified_copy_methods.each do |method_name|
195
- define_method(method_name) do |*a, &b|
196
- modified_copy do |object_to_modify|
197
- responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_ary
198
- responsive_object.public_send(method_name, *a, &b)
199
- end
200
- end
201
- end
202
- safe_el_block_methods.each do |method_name|
203
- define_method(method_name) do |*a, &b|
204
- modified_copy do |object_to_modify|
205
- i = 0
206
- responsive_object = object_to_modify.respond_to?(method_name) ? object_to_modify : object_to_modify.to_ary
207
- responsive_object.public_send(method_name, *a) do |_e|
208
- b.call(self[i]).tap { i += 1 }
209
- end
210
- end
211
- end
212
- end
213
-
214
- # @return [String] basically the same #inspect as Array, but has the
215
- # class name and, if responsive, self's #object_group_text
216
- def inspect
217
- object_group_str = (respond_to?(:object_group_text) ? object_group_text : [self.class]).join(' ')
218
- "\#[<#{object_group_str}>#{empty? ? '' : ' '}#{self.map { |e| e.inspect }.join(', ')}]"
219
- end
220
-
221
- alias_method :to_s, :inspect
222
-
223
- # pretty-prints a representation this node to the given printer
224
- # @return [void]
225
- def pretty_print(q)
226
- object_group_str = (respond_to?(:object_group_text) ? object_group_text : [self.class]).join(' ')
227
- q.text "\#[<#{object_group_str}>"
228
- q.group_sub {
229
- q.nest(2) {
230
- q.breakable(any? { true } ? ' ' : '')
231
- q.seplist(self, nil, :each) { |e|
232
- q.pp e
233
- }
234
- }
235
- }
236
- q.breakable ''
237
- q.text ']'
238
- end
239
- end
240
- end
Binary file
@@ -1,323 +0,0 @@
1
- require_relative 'test_helper'
2
-
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}] }
17
- let(:schema_content) do
18
- {
19
- 'description' => 'hash schema',
20
- 'type' => 'array',
21
- 'items' => [
22
- {'type' => 'string'},
23
- {'type' => 'object'},
24
- {'type' => 'array', 'items' => {}},
25
- ],
26
- }
27
- end
28
- let(:schema) { JSI::Schema.new(schema_content) }
29
- let(:subject) { schema.new_jsi(instance) }
30
-
31
- describe '#[] with a default that is a basic type' do
32
- let(:schema_content) do
33
- {
34
- 'type' => 'array',
35
- 'items' => {'default' => 'foo'},
36
- }
37
- end
38
- describe 'default value' do
39
- let(:instance) { [1] }
40
- it 'returns the default value' do
41
- assert_equal('foo', subject[2])
42
- end
43
- end
44
- describe 'nondefault value (basic type)' do
45
- let(:instance) { ['who'] }
46
- it 'returns the nondefault value' do
47
- assert_equal('who', subject[0])
48
- end
49
- end
50
- describe 'nondefault value (nonbasic type)' do
51
- let(:instance) { [[2]] }
52
- it 'returns the nondefault value' do
53
- assert_is_a(schema.items.jsi_schema_module, subject[0])
54
- assert_equal([2], subject[0].as_json)
55
- end
56
- end
57
- end
58
- describe '#[] with a default that is a nonbasic type' do
59
- let(:schema_content) do
60
- {
61
- 'type' => 'array',
62
- 'items' => {'default' => {'foo' => 2}},
63
- }
64
- end
65
- describe 'default value' do
66
- let(:instance) { [{'bar' => 3}] }
67
- it 'returns the default value' do
68
- assert_is_a(schema.items.jsi_schema_module, subject[1])
69
- assert_equal({'foo' => 2}, subject[1].as_json)
70
- end
71
- end
72
- describe 'nondefault value (basic type)' do
73
- let(:instance) { [true, 'who'] }
74
- it 'returns the nondefault value' do
75
- assert_equal('who', subject[1])
76
- end
77
- end
78
- describe 'nondefault value (nonbasic type)' do
79
- let(:instance) { [true, [2]] }
80
- it 'returns the nondefault value' do
81
- assert_is_a(schema.items.jsi_schema_module, subject[1])
82
- assert_equal([2], subject[1].as_json)
83
- end
84
- end
85
- end
86
- describe 'arraylike []=' do
87
- it 'sets an index' do
88
- orig_2 = subject[2]
89
-
90
- subject[2] = {'y' => 'z'}
91
-
92
- assert_equal({'y' => 'z'}, subject[2].as_json)
93
- assert_is_a(schema.items[2].jsi_schema_module, orig_2)
94
- assert_is_a(schema.items[2].jsi_schema_module, subject[2])
95
- end
96
- it 'modifies the instance, visible to other references to the same instance' do
97
- orig_instance = subject.jsi_instance
98
-
99
- subject[2] = {'y' => 'z'}
100
-
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)
105
- end
106
- describe 'when the instance is not arraylike' do
107
- let(:instance) { nil }
108
- it 'errors' do
109
- err = assert_raises(NoMethodError) { subject[2] = 0 }
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)
221
- end
222
- end
223
- end
224
- # these methods just delegate to Array so not going to test excessively
225
- describe 'index only methods' do
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) }
230
- end
231
- describe 'index + element methods' do
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) }
239
- require 'abbrev'
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([])) }
261
- # due to differences in implementation between #assoc and #rassoc, the reason for which
262
- # I cannot begin to fathom, assoc works but rassoc does not because rassoc has different
263
- # type checking than assoc for the array(like) array elements.
264
- # compare:
265
- # assoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3780-L3813
266
- # rassoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3815-L3847
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')) }
269
- it('#repeated_combination') { assert_equal([[]], subject.repeated_combination(0).to_a) }
270
- it('#repeated_permutation') { assert_equal([[]], subject.repeated_permutation(0).to_a) }
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
297
- end
298
- describe 'modified copy methods' do
299
- it('#reject') { assert_equal(schema.new_jsi(['foo']), subject.reject { |e| e != 'foo' }) }
300
- it('#reject block var') do
301
- subj_a = subject.to_a
302
- subject.reject { |e| assert_equal(e, subj_a.shift) }
303
- end
304
- it('#select') { assert_equal(schema.new_jsi(['foo']), subject.select { |e| e == 'foo' }) }
305
- it('#select block var') do
306
- subj_a = subject.to_a
307
- subject.select { |e| assert_equal(e, subj_a.shift) }
308
- end
309
- it('#compact') { assert_equal(subject, subject.compact) }
310
- describe 'at a depth' do
311
- it('#select') do
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)
315
- end
316
- end
317
- end
318
- JSI::Arraylike::DESTRUCTIVE_METHODS.each do |destructive_method_name|
319
- it("does not respond to destructive method #{destructive_method_name}") do
320
- assert(!subject.respond_to?(destructive_method_name))
321
- end
322
- end
323
- end