jsi 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/LICENSE.md +613 -0
- data/README.md +62 -37
- data/jsi.gemspec +8 -12
- data/lib/jsi.rb +11 -0
- data/lib/jsi/base.rb +196 -258
- data/lib/jsi/base/to_rb.rb +2 -0
- data/lib/jsi/jsi_coder.rb +20 -15
- data/lib/jsi/json-schema-fragments.rb +2 -0
- data/lib/jsi/json.rb +2 -0
- data/lib/jsi/json/node.rb +45 -88
- data/lib/jsi/json/pointer.rb +102 -5
- data/lib/jsi/metaschema.rb +7 -0
- data/lib/jsi/metaschema_node.rb +217 -0
- data/lib/jsi/pathed_node.rb +5 -0
- data/lib/jsi/schema.rb +146 -169
- data/lib/jsi/schema_classes.rb +112 -47
- data/lib/jsi/simple_wrap.rb +8 -3
- data/lib/jsi/typelike_modules.rb +31 -39
- data/lib/jsi/util.rb +27 -47
- data/lib/jsi/version.rb +1 -1
- data/lib/schemas/json-schema.org/draft-04/schema.rb +7 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +7 -0
- data/resources/icons/AGPL-3.0.png +0 -0
- data/test/base_array_test.rb +174 -60
- data/test/base_hash_test.rb +179 -46
- data/test/base_test.rb +163 -94
- data/test/jsi_coder_test.rb +14 -14
- data/test/jsi_json_arraynode_test.rb +10 -10
- data/test/jsi_json_hashnode_test.rb +14 -14
- data/test/jsi_json_node_test.rb +83 -136
- data/test/jsi_typelike_as_json_test.rb +1 -1
- data/test/metaschema_node_test.rb +19 -0
- data/test/schema_module_test.rb +21 -0
- data/test/schema_test.rb +40 -50
- data/test/test_helper.rb +35 -3
- data/test/util_test.rb +8 -8
- metadata +24 -16
- data/LICENSE.txt +0 -21
data/test/jsi_coder_test.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
|
3
3
|
describe JSI::JSICoder do
|
4
|
-
let(:
|
4
|
+
let(:schema_object) do
|
5
5
|
{properties: {foo: {}, bar: {}}}
|
6
6
|
end
|
7
|
-
let(:
|
7
|
+
let(:schema) { JSI::Schema.new(schema_object) }
|
8
8
|
let(:options) { {} }
|
9
|
-
let(:schema_instance_json_coder) { JSI::JSICoder.new(
|
9
|
+
let(:schema_instance_json_coder) { JSI::JSICoder.new(schema, options) }
|
10
10
|
describe 'json' do
|
11
11
|
describe 'load' do
|
12
12
|
it 'loads nil' do
|
13
13
|
assert_nil(schema_instance_json_coder.load(nil))
|
14
14
|
end
|
15
15
|
it 'loads a hash' do
|
16
|
-
assert_equal(
|
16
|
+
assert_equal(schema.new_jsi('foo' => 'bar'), schema_instance_json_coder.load({"foo" => "bar"}))
|
17
17
|
end
|
18
18
|
it 'loads something else' do
|
19
|
-
assert_equal(
|
19
|
+
assert_equal(schema.new_jsi([[]]), schema_instance_json_coder.load([[]]))
|
20
20
|
end
|
21
21
|
describe 'array' do
|
22
22
|
let(:options) { {array: true} }
|
23
23
|
it 'loads an array of hashes' do
|
24
24
|
data = [{"foo" => "bar"}, {"foo" => "baz"}]
|
25
|
-
assert_equal([
|
25
|
+
assert_equal([schema.new_jsi('foo' => 'bar'), schema.new_jsi('foo' => 'baz')], schema_instance_json_coder.load(data))
|
26
26
|
end
|
27
27
|
it 'loads an empty array' do
|
28
28
|
assert_equal([], schema_instance_json_coder.load([]))
|
@@ -34,17 +34,17 @@ describe JSI::JSICoder do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
describe 'array schema' do
|
37
|
-
let(:
|
37
|
+
let(:schema_object) { {items: {properties: {foo: {}, bar: {}}}} }
|
38
38
|
it 'loads an array of hashes' do
|
39
39
|
data = [{"foo" => "bar"}, {"foo" => "baz"}]
|
40
|
-
assert_equal(
|
40
|
+
assert_equal(schema.new_jsi([{'foo' => 'bar'}, {'foo' => 'baz'}]), schema_instance_json_coder.load(data))
|
41
41
|
end
|
42
42
|
it 'loads an empty array' do
|
43
|
-
assert_equal(
|
43
|
+
assert_equal(schema.new_jsi([]), schema_instance_json_coder.load([]))
|
44
44
|
end
|
45
45
|
it 'loads a not an array' do
|
46
46
|
instance = Object.new
|
47
|
-
assert_equal(
|
47
|
+
assert_equal(schema.new_jsi(instance), schema_instance_json_coder.load(instance))
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -53,7 +53,7 @@ describe JSI::JSICoder do
|
|
53
53
|
assert_nil(schema_instance_json_coder.dump(nil))
|
54
54
|
end
|
55
55
|
it 'dumps a schema_instance_class' do
|
56
|
-
assert_equal({"foo" => "x", "bar" => "y"}, schema_instance_json_coder.dump(
|
56
|
+
assert_equal({"foo" => "x", "bar" => "y"}, schema_instance_json_coder.dump(schema.new_jsi(foo: 'x', bar: 'y')))
|
57
57
|
end
|
58
58
|
it 'dumps something else' do
|
59
59
|
assert_raises(TypeError) do
|
@@ -69,14 +69,14 @@ describe JSI::JSICoder do
|
|
69
69
|
describe 'array' do
|
70
70
|
let(:options) { {array: true} }
|
71
71
|
it 'dumps an array of schema_instances' do
|
72
|
-
schema_instances = [
|
72
|
+
schema_instances = [schema.new_jsi(foo: 'x', bar: 'y'), schema.new_jsi(foo: 'z', bar: 'q')]
|
73
73
|
assert_equal([{"foo" => "x", "bar" => "y"}, {"foo" => "z", "bar" => "q"}], schema_instance_json_coder.dump(schema_instances))
|
74
74
|
end
|
75
75
|
end
|
76
76
|
describe 'array schema' do
|
77
|
-
let(:
|
77
|
+
let(:schema_object) { {items: {properties: {foo: {}, bar: {}}}} }
|
78
78
|
it 'dumps a schema_instance array' do
|
79
|
-
schema_instances =
|
79
|
+
schema_instances = schema.new_jsi([{foo: 'x', bar: 'y'}, {foo: 'z', bar: 'q'}])
|
80
80
|
assert_equal([{"foo" => "x", "bar" => "y"}, {"foo" => "z", "bar" => "q"}], schema_instance_json_coder.dump(schema_instances))
|
81
81
|
end
|
82
82
|
end
|
@@ -3,24 +3,24 @@ require_relative 'test_helper'
|
|
3
3
|
document_types = [
|
4
4
|
{
|
5
5
|
make_document: -> (d) { d },
|
6
|
-
|
6
|
+
node_document: ['a', ['b', 'q'], {'c' => {'d' => 'e'}}],
|
7
7
|
type_desc: 'Array',
|
8
8
|
},
|
9
9
|
{
|
10
10
|
make_document: -> (d) { SortOfArray.new(d) },
|
11
|
-
|
11
|
+
node_document: SortOfArray.new(['a', SortOfArray.new(['b', 'q']), SortOfHash.new({'c' => SortOfHash.new({'d' => 'e'})})]),
|
12
12
|
type_desc: 'sort of Array-like',
|
13
13
|
},
|
14
14
|
]
|
15
15
|
document_types.each do |document_type|
|
16
16
|
describe "JSI::JSON::ArrayNode with #{document_type[:type_desc]}" do
|
17
|
-
#
|
18
|
-
let(:
|
17
|
+
# node_document of the node being tested
|
18
|
+
let(:node_document) { document_type[:node_document] }
|
19
19
|
# by default the node is the whole document
|
20
20
|
let(:path) { [] }
|
21
|
-
let(:
|
21
|
+
let(:node_ptr) { JSI::JSON::Pointer.new(path) }
|
22
22
|
# the node being tested
|
23
|
-
let(:node) { JSI::JSON::Node.new_by_type(
|
23
|
+
let(:node) { JSI::JSON::Node.new_by_type(node_document, node_ptr) }
|
24
24
|
|
25
25
|
describe '#[] bad index' do
|
26
26
|
it 'improves TypeError for Array subsript' do
|
@@ -56,7 +56,7 @@ document_types.each do |document_type|
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
describe '#as_json' do
|
59
|
-
let(:
|
59
|
+
let(:node_document) { document_type[:make_document].call(['a', 'b']) }
|
60
60
|
it '#as_json' do
|
61
61
|
assert_equal(['a', 'b'], node.as_json)
|
62
62
|
assert_equal(['a', 'b'], node.as_json(some_option: false))
|
@@ -130,13 +130,13 @@ document_types.each do |document_type|
|
|
130
130
|
describe 'modified copy methods' do
|
131
131
|
it('#reject') { assert_equal(JSI::JSON::Node.new_doc(['a']), node.reject { |e| e != 'a' }) }
|
132
132
|
it('#select') { assert_equal(JSI::JSON::Node.new_doc(['a']), node.select { |e| e == 'a' }) }
|
133
|
-
it('#compact') { assert_equal(JSI::JSON::Node.new_doc(node.
|
133
|
+
it('#compact') { assert_equal(JSI::JSON::Node.new_doc(node.node_content.to_ary), node.compact) }
|
134
134
|
describe 'at a depth' do
|
135
|
-
let(:
|
135
|
+
let(:node_document) { document_type[:make_document].call([['b', 'q'], {'c' => ['d', 'e']}]) }
|
136
136
|
let(:path) { ['1', 'c'] }
|
137
137
|
it('#select') do
|
138
138
|
selected = node.select { |e| e == 'd' }
|
139
|
-
equivalent = JSI::JSON::Node.new_by_type([['b', 'q'], {'c' => ['d']}],
|
139
|
+
equivalent = JSI::JSON::Node.new_by_type([['b', 'q'], {'c' => ['d']}], node_ptr)
|
140
140
|
assert_equal(equivalent, selected)
|
141
141
|
end
|
142
142
|
end
|
@@ -3,24 +3,24 @@ require_relative 'test_helper'
|
|
3
3
|
document_types = [
|
4
4
|
{
|
5
5
|
make_document: -> (d) { d },
|
6
|
-
|
6
|
+
node_document: {'a' => 'b', 'c' => {'d' => 'e'}},
|
7
7
|
type_desc: 'Hash',
|
8
8
|
},
|
9
9
|
{
|
10
10
|
make_document: -> (d) { SortOfHash.new(d) },
|
11
|
-
|
11
|
+
node_document: SortOfHash.new({'a' => 'b', 'c' => SortOfHash.new({'d' => 'e'})}),
|
12
12
|
type_desc: 'sort of Hash-like',
|
13
13
|
},
|
14
14
|
]
|
15
15
|
document_types.each do |document_type|
|
16
16
|
describe "JSI::JSON::HashNode with #{document_type[:type_desc]}" do
|
17
|
-
#
|
18
|
-
let(:
|
17
|
+
# node_document of the node being tested
|
18
|
+
let(:node_document) { document_type[:node_document] }
|
19
19
|
# by default the node is the whole document
|
20
20
|
let(:path) { [] }
|
21
|
-
let(:
|
21
|
+
let(:node_ptr) { JSI::JSON::Pointer.new(path) }
|
22
22
|
# the node being tested
|
23
|
-
let(:node) { JSI::JSON::Node.new_by_type(
|
23
|
+
let(:node) { JSI::JSON::Node.new_by_type(node_document, node_ptr) }
|
24
24
|
|
25
25
|
describe '#each' do
|
26
26
|
it 'iterates, one argument' do
|
@@ -55,21 +55,21 @@ document_types.each do |document_type|
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
describe '#merge' do
|
58
|
-
let(:
|
58
|
+
let(:node_document) { document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}) }
|
59
59
|
# testing the node at 'c' here, merging a hash at a path within a document.
|
60
60
|
let(:path) { ['c'] }
|
61
61
|
it 'merges' do
|
62
62
|
merged = node.merge('x' => 'y')
|
63
|
-
# check the
|
64
|
-
assert_equal({'a' => {'b' => 0}, 'c' => {'d' => 'e', 'x' => 'y'}}, merged.
|
63
|
+
# check the node_content at 'c' was merged with the remainder of the document intact (at 'a')
|
64
|
+
assert_equal({'a' => {'b' => 0}, 'c' => {'d' => 'e', 'x' => 'y'}}, merged.node_document)
|
65
65
|
# check the original node retains its original document
|
66
|
-
assert_equal(document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}), node.
|
66
|
+
assert_equal(document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}), node.node_document)
|
67
67
|
# check that unnecessary copies of unaffected parts of the document were not made
|
68
|
-
assert_equal(node.
|
68
|
+
assert_equal(node.node_document.to_hash['a'].object_id, merged.node_document['a'].object_id)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
describe '#as_json' do
|
72
|
-
let(:
|
72
|
+
let(:node_document) { document_type[:make_document].call({'a' => 'b'}) }
|
73
73
|
it '#as_json' do
|
74
74
|
assert_equal({'a' => 'b'}, node.as_json)
|
75
75
|
assert_equal({'a' => 'b'}, node.as_json(this_option: 'what?'))
|
@@ -115,12 +115,12 @@ document_types.each do |document_type|
|
|
115
115
|
describe 'modified copy methods' do
|
116
116
|
# I'm going to rely on the #merge test above to test the modified copy functionality and just do basic
|
117
117
|
# tests of all the modified copy methods here
|
118
|
-
it('#merge') { assert_equal(JSI::JSON::Node.new_doc(node.
|
118
|
+
it('#merge') { assert_equal(JSI::JSON::Node.new_doc(node.node_content), node.merge({})) }
|
119
119
|
it('#reject') { assert_equal(JSI::JSON::Node.new_doc({}), node.reject { true }) }
|
120
120
|
it('#select') { assert_equal(JSI::JSON::Node.new_doc({}), node.select { false }) }
|
121
121
|
# Hash#compact only available as of ruby 2.5.0
|
122
122
|
if {}.respond_to?(:compact)
|
123
|
-
it('#compact') { assert_equal(JSI::JSON::Node.new_doc({"a" => "b", "c" => node.
|
123
|
+
it('#compact') { assert_equal(JSI::JSON::Node.new_doc({"a" => "b", "c" => node.node_content.to_hash["c"]}), node.compact) }
|
124
124
|
end
|
125
125
|
end
|
126
126
|
JSI::Hashlike::DESTRUCTIVE_METHODS.each do |destructive_method_name|
|
data/test/jsi_json_node_test.rb
CHANGED
@@ -2,75 +2,70 @@ require_relative 'test_helper'
|
|
2
2
|
|
3
3
|
describe JSI::JSON::Node do
|
4
4
|
let(:path) { [] }
|
5
|
-
let(:
|
6
|
-
let(:node) { JSI::JSON::Node.new(
|
5
|
+
let(:node_ptr) { JSI::JSON::Pointer.new(path) }
|
6
|
+
let(:node) { JSI::JSON::Node.new(node_document, node_ptr) }
|
7
7
|
|
8
8
|
describe 'initialization' do
|
9
9
|
it 'initializes' do
|
10
|
-
node = JSI::JSON::Node.new({'a' => 'b'},
|
11
|
-
assert_equal({'a' => 'b'}, node.
|
12
|
-
assert_equal(JSI::JSON::Pointer.new([]), node.
|
10
|
+
node = JSI::JSON::Node.new({'a' => 'b'}, node_ptr)
|
11
|
+
assert_equal({'a' => 'b'}, node.node_document)
|
12
|
+
assert_equal(JSI::JSON::Pointer.new([]), node.node_ptr)
|
13
13
|
end
|
14
|
-
it 'initializes,
|
14
|
+
it 'initializes, node_ptr is not node_ptr' do
|
15
15
|
err = assert_raises(TypeError) { JSI::JSON::Node.new({'a' => 'b'}, []) }
|
16
|
-
assert_equal('
|
16
|
+
assert_equal('node_ptr must be a JSI::JSON::Pointer. got: [] (Array)', err.message)
|
17
17
|
end
|
18
|
-
it 'initializes,
|
19
|
-
err = assert_raises(TypeError) { JSI::JSON::Node.new(JSI::JSON::Node.new({'a' => 'b'},
|
20
|
-
assert_equal("
|
18
|
+
it 'initializes, node_document is another Node' do
|
19
|
+
err = assert_raises(TypeError) { JSI::JSON::Node.new(JSI::JSON::Node.new({'a' => 'b'}, node_ptr), node_ptr) }
|
20
|
+
assert_equal("node_document of a Node should not be another JSI::JSON::Node: #<JSI::JSON::Node fragment=\"#\" {\"a\"=>\"b\"}>", err.message)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
describe 'initialization by .new_by_type' do
|
24
24
|
it 'initializes HashNode' do
|
25
25
|
node = JSI::JSON::Node.new_doc({'a' => 'b'})
|
26
26
|
assert_instance_of(JSI::JSON::HashNode, node)
|
27
|
-
assert_equal({'a' => 'b'}, node.
|
27
|
+
assert_equal({'a' => 'b'}, node.node_document)
|
28
28
|
end
|
29
29
|
it 'initializes ArrayNode' do
|
30
30
|
node = JSI::JSON::Node.new_doc(['a', 'b'])
|
31
31
|
assert_instance_of(JSI::JSON::ArrayNode, node)
|
32
|
-
assert_equal(['a', 'b'], node.
|
32
|
+
assert_equal(['a', 'b'], node.node_document)
|
33
33
|
end
|
34
34
|
it 'initializes Node' do
|
35
35
|
object = Object.new
|
36
36
|
node = JSI::JSON::Node.new_doc(object)
|
37
37
|
assert_instance_of(JSI::JSON::Node, node)
|
38
|
-
assert_equal(object, node.
|
38
|
+
assert_equal(object, node.node_document)
|
39
39
|
end
|
40
40
|
end
|
41
|
-
describe '#
|
41
|
+
describe '#node_ptr' do
|
42
42
|
it 'is a JSI::JSON::Pointer' do
|
43
|
-
assert_instance_of(JSI::JSON::Pointer, JSI::JSON::Node.new({},
|
43
|
+
assert_instance_of(JSI::JSON::Pointer, JSI::JSON::Node.new({}, node_ptr).node_ptr)
|
44
44
|
end
|
45
45
|
end
|
46
|
-
describe '#
|
47
|
-
it '
|
48
|
-
assert_equal(
|
46
|
+
describe '#node_content' do
|
47
|
+
it 'returns the node_content at the root' do
|
48
|
+
assert_equal({'a' => 'b'}, JSI::JSON::Node.new({'a' => 'b'}, node_ptr).node_content)
|
49
49
|
end
|
50
|
-
|
51
|
-
|
52
|
-
it 'returns the content at the root' do
|
53
|
-
assert_equal({'a' => 'b'}, JSI::JSON::Node.new({'a' => 'b'}, pointer).content)
|
54
|
-
end
|
55
|
-
it 'returns the content from the deep' do
|
56
|
-
assert_equal('b', JSI::JSON::Node.new([0, {'x' => [{'a' => ['b']}]}], JSI::JSON::Pointer.new([1, 'x', 0, 'a', 0])).content)
|
50
|
+
it 'returns the node_content from the deep' do
|
51
|
+
assert_equal('b', JSI::JSON::Node.new([0, {'x' => [{'a' => ['b']}]}], JSI::JSON::Pointer.new([1, 'x', 0, 'a', 0])).node_content)
|
57
52
|
end
|
58
53
|
end
|
59
54
|
describe '#deref' do
|
60
|
-
let(:
|
55
|
+
let(:node_document) do
|
61
56
|
{
|
62
57
|
'foo' => {'bar' => ['baz']},
|
63
58
|
'a' => {'$ref' => '#/foo'},
|
64
59
|
}
|
65
60
|
end
|
66
61
|
it 'follows a $ref' do
|
67
|
-
assert_equal({'bar' => ['baz']}, node['a'].deref.
|
62
|
+
assert_equal({'bar' => ['baz']}, node['a'].deref.node_content)
|
68
63
|
end
|
69
64
|
it 'returns the node when there is no $ref to follow' do
|
70
|
-
assert_equal({'bar' => ['baz']}, node['foo'].deref.
|
65
|
+
assert_equal({'bar' => ['baz']}, node['foo'].deref.node_content)
|
71
66
|
end
|
72
67
|
describe "dealing with google's invalid $refs" do
|
73
|
-
let(:
|
68
|
+
let(:node_document) do
|
74
69
|
{
|
75
70
|
'schemas' => {'bar' => {'description' => ['baz']}},
|
76
71
|
'a' => {'$ref' => 'bar', 'foo' => 'bar'},
|
@@ -78,118 +73,100 @@ describe JSI::JSON::Node do
|
|
78
73
|
end
|
79
74
|
it 'subscripts a node consisting of a $ref WITHOUT following' do
|
80
75
|
subscripted = node['a']
|
81
|
-
assert_equal({'$ref' => 'bar', 'foo' => 'bar'}, subscripted.
|
82
|
-
assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.
|
76
|
+
assert_equal({'$ref' => 'bar', 'foo' => 'bar'}, subscripted.node_content)
|
77
|
+
assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.node_ptr)
|
83
78
|
end
|
84
79
|
it 'looks for a node in #/schemas with the name of the $ref' do
|
85
|
-
assert_equal({'description' => ['baz']}, node['a'].deref.
|
86
|
-
end
|
87
|
-
it 'follows a $ref when subscripting past it' do
|
88
|
-
subscripted = node['a']['description']
|
89
|
-
assert_equal(['baz'], subscripted.content)
|
90
|
-
assert_equal(JSI::JSON::Pointer.new(['schemas', 'bar', 'description']), subscripted.pointer)
|
91
|
-
end
|
92
|
-
it 'does not follow a $ref when subscripting a key that is present' do
|
93
|
-
subscripted = node['a']['foo']
|
94
|
-
assert_equal('bar', subscripted)
|
80
|
+
assert_equal({'description' => ['baz']}, node['a'].deref.node_content)
|
95
81
|
end
|
96
82
|
end
|
97
83
|
describe "dealing with whatever this is" do
|
98
84
|
# I think google uses this style in some cases maybe. I don't remember.
|
99
|
-
let(:
|
85
|
+
let(:node_document) do
|
100
86
|
{
|
101
87
|
'schemas' => {'bar' => {'id' => 'BarID', 'description' => 'baz'}},
|
102
88
|
'a' => {'$ref' => 'BarID'},
|
103
89
|
}
|
104
90
|
end
|
105
91
|
it 'looks for a node in #/schemas with the name of the $ref' do
|
106
|
-
assert_equal({'id' => 'BarID', 'description' => 'baz'}, node['a'].deref.
|
92
|
+
assert_equal({'id' => 'BarID', 'description' => 'baz'}, node['a'].deref.node_content)
|
107
93
|
end
|
108
94
|
end
|
109
95
|
end
|
110
96
|
describe '#[]' do
|
111
97
|
describe 'without dereferencing' do
|
112
|
-
let(:
|
98
|
+
let(:node_document) { [0, {'x' => [{'a' => ['b']}]}] }
|
113
99
|
it 'subscripts arrays and hashes' do
|
114
100
|
assert_equal('b', node[1]['x'][0]['a'][0])
|
115
101
|
end
|
116
102
|
it 'returns ArrayNode for an array' do
|
117
103
|
subscripted = node[1]['x']
|
118
104
|
assert_instance_of(JSI::JSON::ArrayNode, subscripted)
|
119
|
-
assert_equal([{'a' => ['b']}], subscripted.
|
120
|
-
assert_equal(JSI::JSON::Pointer.new([1, 'x']), subscripted.
|
105
|
+
assert_equal([{'a' => ['b']}], subscripted.node_content)
|
106
|
+
assert_equal(JSI::JSON::Pointer.new([1, 'x']), subscripted.node_ptr)
|
121
107
|
end
|
122
108
|
it 'returns HashNode for a Hash' do
|
123
109
|
subscripted = node[1]
|
124
110
|
assert_instance_of(JSI::JSON::HashNode, subscripted)
|
125
|
-
assert_equal({'x' => [{'a' => ['b']}]}, subscripted.
|
126
|
-
assert_equal(JSI::JSON::Pointer.new([1]), subscripted.
|
111
|
+
assert_equal({'x' => [{'a' => ['b']}]}, subscripted.node_content)
|
112
|
+
assert_equal(JSI::JSON::Pointer.new([1]), subscripted.node_ptr)
|
127
113
|
end
|
128
|
-
describe '
|
129
|
-
let(:
|
114
|
+
describe 'node_content does not respond to []' do
|
115
|
+
let(:node_document) { Object.new }
|
130
116
|
it 'cannot subscript' do
|
131
117
|
err = assert_raises(NoMethodError) { node['x'] }
|
132
|
-
assert_equal("undefined method `[]`\nsubscripting with \"x\" (String) from Object. content is: #{
|
118
|
+
assert_equal("undefined method `[]`\nsubscripting with \"x\" (String) from Object. content is: #{node_document.pretty_inspect.chomp}", err.message)
|
133
119
|
end
|
134
120
|
end
|
135
121
|
end
|
136
122
|
describe 'with dereferencing' do
|
137
|
-
let(:
|
123
|
+
let(:node_document) do
|
138
124
|
{
|
139
125
|
'foo' => {'bar' => ['baz']},
|
140
126
|
'a' => {'$ref' => '#/foo', 'description' => 'hi'}, # not sure a description is actually allowed here, whatever
|
141
127
|
}
|
142
128
|
end
|
143
|
-
it 'subscripts a node consisting of a $ref
|
129
|
+
it 'subscripts a node consisting of a $ref without following' do
|
144
130
|
subscripted = node['a']
|
145
|
-
assert_equal({'$ref' => '#/foo', 'description' => 'hi'}, subscripted.
|
146
|
-
assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.
|
147
|
-
end
|
148
|
-
it 'follows a $ref when subscripting past it' do
|
149
|
-
subscripted = node['a']['bar']
|
150
|
-
assert_equal(['baz'], subscripted.content)
|
151
|
-
assert_equal(JSI::JSON::Pointer.new(['foo', 'bar']), subscripted.pointer)
|
152
|
-
end
|
153
|
-
it 'does not follow a $ref when subscripting a key that is present' do
|
154
|
-
subscripted = node['a']['description']
|
155
|
-
assert_equal('hi', subscripted)
|
131
|
+
assert_equal({'$ref' => '#/foo', 'description' => 'hi'}, subscripted.node_content)
|
132
|
+
assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.node_ptr)
|
156
133
|
end
|
157
134
|
end
|
158
135
|
end
|
159
136
|
describe '#[]=' do
|
160
|
-
let(:
|
137
|
+
let(:node_document) { [0, {'x' => [{'a' => ['b']}]}] }
|
161
138
|
it 'assigns' do
|
162
139
|
node[0] = 'abcdefg'
|
163
|
-
assert_equal(['abcdefg', {'x' => [{'a' => ['b']}]}],
|
164
|
-
string_node = JSI::JSON::Node.new(
|
140
|
+
assert_equal(['abcdefg', {'x' => [{'a' => ['b']}]}], node_document)
|
141
|
+
string_node = JSI::JSON::Node.new(node_document, JSI::JSON::Pointer.new([0]))
|
165
142
|
string_node[0..2] = '0'
|
166
|
-
assert_equal(['0defg', {'x' => [{'a' => ['b']}]}],
|
143
|
+
assert_equal(['0defg', {'x' => [{'a' => ['b']}]}], node_document)
|
167
144
|
node[0] = node[1]
|
168
|
-
assert_equal([{'x' => [{'a' => ['b']}]}, {'x' => [{'a' => ['b']}]}],
|
145
|
+
assert_equal([{'x' => [{'a' => ['b']}]}, {'x' => [{'a' => ['b']}]}], node_document)
|
169
146
|
end
|
170
147
|
it 'assigns, deeper' do
|
171
148
|
node[1]['y'] = node[1]['x'][0]
|
172
|
-
assert_equal([0, {'x' => [{'a' => ['b']}], 'y' => {'a' => ['b']}}],
|
149
|
+
assert_equal([0, {'x' => [{'a' => ['b']}], 'y' => {'a' => ['b']}}], node_document)
|
173
150
|
end
|
174
151
|
end
|
175
|
-
describe '#
|
176
|
-
let(:
|
177
|
-
it 'has
|
178
|
-
assert_equal({'a' => {'b' => 3}}, node['a'].
|
152
|
+
describe '#document_root_node' do
|
153
|
+
let(:node_document) { {'a' => {'b' => 3}} }
|
154
|
+
it 'has node_content that is the node_document' do
|
155
|
+
assert_equal({'a' => {'b' => 3}}, node['a'].document_root_node.node_content)
|
179
156
|
end
|
180
157
|
end
|
181
158
|
describe '#parent_node' do
|
182
|
-
let(:
|
159
|
+
let(:node_document) { {'a' => {'b' => []}} }
|
183
160
|
it 'finds a parent' do
|
184
161
|
sub = node['a']['b']
|
185
|
-
assert_equal(JSI::JSON::Pointer.new(['a', 'b']), sub.
|
162
|
+
assert_equal(JSI::JSON::Pointer.new(['a', 'b']), sub.node_ptr)
|
186
163
|
parent = sub.parent_node
|
187
|
-
assert_equal(JSI::JSON::Pointer.new(['a']), parent.
|
188
|
-
assert_equal({'b' => []}, parent.
|
164
|
+
assert_equal(JSI::JSON::Pointer.new(['a']), parent.node_ptr)
|
165
|
+
assert_equal({'b' => []}, parent.node_content)
|
189
166
|
assert_equal(node['a'], parent)
|
190
167
|
root_from_sub = sub.parent_node.parent_node
|
191
|
-
assert_equal(JSI::JSON::Pointer.new([]), root_from_sub.
|
192
|
-
assert_equal({'a' => {'b' => []}}, root_from_sub.
|
168
|
+
assert_equal(JSI::JSON::Pointer.new([]), root_from_sub.node_ptr)
|
169
|
+
assert_equal({'a' => {'b' => []}}, root_from_sub.node_content)
|
193
170
|
assert_equal(node, root_from_sub)
|
194
171
|
err = assert_raises(JSI::JSON::Pointer::ReferenceError) do
|
195
172
|
root_from_sub.parent_node
|
@@ -197,51 +174,21 @@ describe JSI::JSON::Node do
|
|
197
174
|
assert_match(/\Acannot access parent of root pointer: #<JSI::JSON::Pointer/, err.message)
|
198
175
|
end
|
199
176
|
end
|
200
|
-
describe '#pointer_path' do
|
201
|
-
let(:document) { {'a' => {'b' => 3}} }
|
202
|
-
it 'is empty' do
|
203
|
-
assert_equal('', node.pointer_path)
|
204
|
-
end
|
205
|
-
it 'is not empty' do
|
206
|
-
assert_equal('/a', node['a'].pointer_path)
|
207
|
-
end
|
208
|
-
describe 'containing an empty string and some slashes and tildes that need escaping' do
|
209
|
-
let(:document) { {'' => {'a/b~c!d#e[f]' => []}} }
|
210
|
-
it 'matches' do
|
211
|
-
assert_equal('//a~1b~0c!d#e[f]', node['']['a/b~c!d#e[f]'].pointer_path)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
describe '#fragment' do
|
216
|
-
let(:document) { {'a' => {'b' => 3}} }
|
217
|
-
it 'is empty' do
|
218
|
-
assert_equal('#', node.fragment)
|
219
|
-
end
|
220
|
-
it 'is not empty' do
|
221
|
-
assert_equal('#/a', node['a'].fragment)
|
222
|
-
end
|
223
|
-
describe 'containing an empty string and some slashes and tildes that need escaping' do
|
224
|
-
let(:document) { {'' => {'a/b~c!d#e[f]' => []}} }
|
225
|
-
it 'matches' do
|
226
|
-
assert_equal('#//a~1b~0c!d#e%5Bf%5D', node['']['a/b~c!d#e[f]'].fragment)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
177
|
describe '#modified_copy' do
|
231
|
-
let(:
|
178
|
+
let(:node_document) { [['b', 'q'], {'c' => ['d', 'e']}] }
|
232
179
|
let(:path) { ['1', 'c'] }
|
233
180
|
it 'returns a different object' do
|
234
181
|
# simplest thing
|
235
182
|
modified_dup = node.modified_copy(&:dup)
|
236
183
|
# it is equal - being a dup
|
237
|
-
assert_equal(
|
184
|
+
assert_equal(node, modified_dup)
|
238
185
|
# but different object
|
239
186
|
refute_equal(node.object_id, modified_dup.object_id)
|
240
187
|
# the parents, obviously, are different
|
241
|
-
refute_equal(node.parent_node.
|
242
|
-
refute_equal(node.parent_node.parent_node.
|
243
|
-
# but any untouched part(s) - in this case the ['b', 'q'] at
|
244
|
-
assert_equal(node.
|
188
|
+
refute_equal(node.parent_node.node_content.object_id, modified_dup.parent_node.node_content.object_id)
|
189
|
+
refute_equal(node.parent_node.parent_node.node_content.object_id, modified_dup.parent_node.parent_node.node_content.object_id)
|
190
|
+
# but any untouched part(s) - in this case the ['b', 'q'] at node_document[0] - are untouched
|
191
|
+
assert_equal(node.document_root_node[0].node_content.object_id, modified_dup.document_root_node[0].node_content.object_id)
|
245
192
|
end
|
246
193
|
it 'returns the same object' do
|
247
194
|
unmodified_dup = node.modified_copy { |o| o }
|
@@ -249,60 +196,60 @@ describe JSI::JSON::Node do
|
|
249
196
|
# same object, since the block just returned it
|
250
197
|
refute_equal(node.object_id, unmodified_dup.object_id)
|
251
198
|
# the parents are unchanged since the object is the same
|
252
|
-
assert_equal(node.parent_node.
|
253
|
-
assert_equal(node.parent_node.parent_node.
|
254
|
-
# same as the other: any untouched part(s) - in this case the ['b', 'q'] at
|
255
|
-
assert_equal(node.
|
199
|
+
assert_equal(node.parent_node.node_content.object_id, unmodified_dup.parent_node.node_content.object_id)
|
200
|
+
assert_equal(node.parent_node.parent_node.node_content.object_id, unmodified_dup.parent_node.parent_node.node_content.object_id)
|
201
|
+
# same as the other: any untouched part(s) - in this case the ['b', 'q'] at node_document[0] - are untouched
|
202
|
+
assert_equal(node.document_root_node[0].node_content.object_id, unmodified_dup.document_root_node[0].node_content.object_id)
|
256
203
|
end
|
257
204
|
it 'raises subscripting string from array' do
|
258
|
-
err = assert_raises(TypeError) { JSI::JSON::Node.new(
|
205
|
+
err = assert_raises(TypeError) { JSI::JSON::Node.new(node_document, JSI::JSON::Pointer.new(['x'])).modified_copy(&:dup) }
|
259
206
|
assert_match(%r(\Abad subscript "x" with remaining subpath: \[\] for array: \[.*\]\z)m, err.message)
|
260
207
|
end
|
261
208
|
it 'raises subscripting from invalid subpath' do
|
262
|
-
err = assert_raises(TypeError) { JSI::JSON::Node.new(
|
209
|
+
err = assert_raises(TypeError) { JSI::JSON::Node.new(node_document, JSI::JSON::Pointer.new([0, 0, 'what'])).modified_copy(&:dup) }
|
263
210
|
assert_match(%r(bad subscript: "what" with remaining subpath: \[\] for content: "b"\z)m, err.message)
|
264
211
|
end
|
265
212
|
end
|
266
213
|
describe '#inspect' do
|
267
|
-
let(:
|
214
|
+
let(:node_document) { {'a' => {'c' => ['d', 'e']}} }
|
268
215
|
let(:path) { ['a'] }
|
269
216
|
it 'inspects' do
|
270
217
|
assert_equal(%Q(#<JSI::JSON::Node fragment="#/a" {"c"=>["d", "e"]}>), node.inspect)
|
271
218
|
end
|
272
219
|
end
|
273
220
|
describe '#pretty_print' do
|
274
|
-
let(:
|
221
|
+
let(:node_document) { {'a' => {'c' => ['d', 'e']}} }
|
275
222
|
let(:path) { ['a'] }
|
276
223
|
it 'pretty prints' do
|
277
224
|
assert_equal(%Q(#<JSI::JSON::Node fragment="#/a" {"c"=>["d", "e"]}>), node.pretty_inspect.chomp)
|
278
225
|
end
|
279
226
|
end
|
280
|
-
describe '#
|
281
|
-
let(:
|
227
|
+
describe '#jsi_fingerprint' do
|
228
|
+
let(:node_ptr) { JSI::JSON::Pointer.new([]) }
|
282
229
|
it 'hashes consistently' do
|
283
|
-
assert_equal('x', {JSI::JSON::Node.new([0],
|
230
|
+
assert_equal('x', {JSI::JSON::Node.new([0], node_ptr) => 'x'}[JSI::JSON::Node.new([0], node_ptr)])
|
284
231
|
end
|
285
232
|
it 'hashes consistently regardless of the Node being decorated as a subclass' do
|
286
|
-
assert_equal('x', {JSI::JSON::Node.new_doc([0]) => 'x'}[JSI::JSON::Node.new([0],
|
287
|
-
assert_equal('x', {JSI::JSON::Node.new([0],
|
233
|
+
assert_equal('x', {JSI::JSON::Node.new_doc([0]) => 'x'}[JSI::JSON::Node.new([0], node_ptr)])
|
234
|
+
assert_equal('x', {JSI::JSON::Node.new([0], node_ptr) => 'x'}[JSI::JSON::Node.new_doc([0])])
|
288
235
|
end
|
289
236
|
it '==' do
|
290
|
-
assert_equal(JSI::JSON::Node.new([0],
|
291
|
-
assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new([0],
|
292
|
-
assert_equal(JSI::JSON::Node.new([0],
|
237
|
+
assert_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new([0], node_ptr))
|
238
|
+
assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new([0], node_ptr))
|
239
|
+
assert_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new_doc([0]))
|
293
240
|
assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc([0]))
|
294
241
|
end
|
295
242
|
it '!=' do
|
296
|
-
refute_equal(JSI::JSON::Node.new([0],
|
297
|
-
refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new({},
|
298
|
-
refute_equal(JSI::JSON::Node.new([0],
|
243
|
+
refute_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new({}, node_ptr))
|
244
|
+
refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new({}, node_ptr))
|
245
|
+
refute_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new_doc({}))
|
299
246
|
refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc({}))
|
300
247
|
refute_equal({}, JSI::JSON::Node.new_doc({}))
|
301
248
|
refute_equal(JSI::JSON::Node.new_doc({}), {})
|
302
249
|
end
|
303
250
|
end
|
304
251
|
describe '#as_json' do
|
305
|
-
let(:
|
252
|
+
let(:node_document) { {'a' => 'b'} }
|
306
253
|
it '#as_json' do
|
307
254
|
assert_equal({'a' => 'b'}, node.as_json)
|
308
255
|
end
|