jsi 0.4.0 → 0.7.0

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