json-pointer 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +27 -0
- data/README.md +87 -0
- data/Rakefile +8 -0
- data/json-pointer.gemspec +22 -0
- data/lib/json-pointer.rb +169 -0
- data/lib/json-pointer/version.rb +3 -0
- data/spec/json_pointer_spec.rb +303 -0
- data/spec/spec_helper.rb +10 -0
- metadata +89 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2013 Apollic Software, LLC. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions are
|
5
|
+
met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above
|
10
|
+
copyright notice, this list of conditions and the following disclaimer
|
11
|
+
in the documentation and/or other materials provided with the
|
12
|
+
distribution.
|
13
|
+
* Neither the name of Apollic Software, LLC nor the names of its
|
14
|
+
contributors may be used to endorse or promote products derived from
|
15
|
+
this software without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
18
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
19
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
20
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
21
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# JsonPointer [](https://travis-ci.org/tent/json-pointer-ruby)
|
2
|
+
|
3
|
+
[JSON Pointer](http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-09) implementation.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'json-pointer'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install json-pointer
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
hash = { :foo => { :bar => [{ :baz => "foobar" }, { :hello => "world" }, { :baz => "water" }] } }
|
23
|
+
|
24
|
+
## Simple pointer
|
25
|
+
|
26
|
+
pointer = JsonPointer.new(hash, "/foo/bar", :symbolize_keys => true)
|
27
|
+
pointer.exists? # => true
|
28
|
+
pointer.value # => [{ :baz => "foobar" }, { :hello => "world" }, { :baz => "water" }]
|
29
|
+
|
30
|
+
pointer = JsonPointer.new(hash, "/baz/bar/foo", :symbolize_keys => true)
|
31
|
+
pointer.exists? # => false
|
32
|
+
pointer.value = "Hello World!"
|
33
|
+
hash[:baz] # => { :bar => { :foo => "Hello World" } }
|
34
|
+
|
35
|
+
pointer = JsonPointer.new(hash, "/biz", :symbolize_keys => true)
|
36
|
+
pointer.exists? # => false
|
37
|
+
pointer.value # => nil
|
38
|
+
|
39
|
+
## Simple pointer with Array index
|
40
|
+
|
41
|
+
pointer = JsonPointer.new(hash, "/foo/bar/0/baz", :symbolize_keys => true)
|
42
|
+
pointer.value # => "foobar"
|
43
|
+
|
44
|
+
## Insert member into array specific index
|
45
|
+
|
46
|
+
pointer = JsonPointer.new(hash, "/foo/bar/1", :symbolize_keys => true)
|
47
|
+
pointer.value = { :baz => "foo" }
|
48
|
+
hash[:foo][:bar] # => [{ :baz => "foobar" }, { :baz => "foo" }, { :hello => "world" }, { :baz => "water" }]
|
49
|
+
|
50
|
+
## Append member to array
|
51
|
+
|
52
|
+
pointer = JsonPointer.new(hash, "/foo/bar/-", :symbolize_keys => true)
|
53
|
+
pointer.value = { :baz => "bar" }
|
54
|
+
hash[:foo][:bar] # => [{ :baz => "foobar" }, { :baz => "foo" }, { :hello => "world" }, { :baz => "water" }, { :baz => "bar" }]
|
55
|
+
|
56
|
+
## Delete array member
|
57
|
+
|
58
|
+
pointer = JsonPointer.new(hash, "/foo/bar/1", :symbolize_keys => true)
|
59
|
+
pointer.delete
|
60
|
+
hash[:foo][:bar] # => [{ :baz => "foobar" }, { :hello => "world" }, { :baz => "water" }, { :baz => "bar" }]
|
61
|
+
pointer.delete
|
62
|
+
hash[:foo][:bar] # => [{ :baz => "foobar" }, { :baz => "water" }, { :baz => "bar" }]
|
63
|
+
|
64
|
+
## Array index Wildcard (NOTE: this is not part of the spec)
|
65
|
+
|
66
|
+
pointer = JsonPointer.new(hash, "/foo/bar/*/baz", :symbolize_keys => true)
|
67
|
+
pointer.value # => ["foobar", nil, "water"]
|
68
|
+
|
69
|
+
pointer = JsonPointer.new(hash, "/foo/bar/*/fire", :symbolize_keys => true)
|
70
|
+
pointer.value = "dirt"
|
71
|
+
pointer.value # => ["dirt", "dirt", "dirt"]
|
72
|
+
hash[:foo][:bar] # => [{ :baz => "foobar", :fire => "dirt" }, { :baz => "water", :fire => "dirt" }, { :baz => "bar", :fire => "dirt" }]
|
73
|
+
```
|
74
|
+
|
75
|
+
### Options
|
76
|
+
|
77
|
+
name | description
|
78
|
+
---- | -----------
|
79
|
+
symbolize_keys | Set to `true` if the hash uses symbols for keys. Default is `false`.
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'json-pointer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "json-pointer"
|
8
|
+
gem.version = JsonPointer::VERSION
|
9
|
+
gem.authors = ["Jesse Stuart"]
|
10
|
+
gem.email = ["jesse@jessestuart.ca"]
|
11
|
+
gem.description = %q{JSON Pointer implementation}
|
12
|
+
gem.summary = %q{JSON Pointer implementation}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rspec', '~> 2.11'
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
end
|
data/lib/json-pointer.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require "json-pointer/version"
|
2
|
+
|
3
|
+
class JsonPointer
|
4
|
+
|
5
|
+
NotFound = Class.new
|
6
|
+
WILDCARD = "*".freeze
|
7
|
+
ARRAY_PUSH_KEY = '-'.freeze
|
8
|
+
|
9
|
+
def initialize(hash, path, options = {})
|
10
|
+
@hash, @path, @options = hash, path, options
|
11
|
+
end
|
12
|
+
|
13
|
+
def value
|
14
|
+
get_member_value
|
15
|
+
end
|
16
|
+
|
17
|
+
def value=(new_value)
|
18
|
+
set_member_value(new_value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete
|
22
|
+
delete_member
|
23
|
+
end
|
24
|
+
|
25
|
+
def exists?
|
26
|
+
_exists = false
|
27
|
+
get_target_member(@hash, path_fragments.dup) do |target|
|
28
|
+
_exists = true unless NotFound === target
|
29
|
+
end
|
30
|
+
_exists
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_member_value(obj = @hash, fragments = path_fragments.dup)
|
36
|
+
return obj if fragments.empty?
|
37
|
+
|
38
|
+
fragment = fragments.shift
|
39
|
+
case obj
|
40
|
+
when Hash
|
41
|
+
get_member_value(obj[fragment_to_key(fragment)], fragments)
|
42
|
+
when Array
|
43
|
+
if fragment == WILDCARD
|
44
|
+
obj.map { |i| get_member_value(i, fragments.dup) }
|
45
|
+
else
|
46
|
+
get_member_value(obj[fragment_to_index(fragment)], fragments)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_target_member(obj, fragments, options = {}, &block)
|
52
|
+
return yield(obj) if fragments.empty?
|
53
|
+
|
54
|
+
fragment = fragments.shift
|
55
|
+
case obj
|
56
|
+
when Hash
|
57
|
+
key = fragment_to_key(fragment)
|
58
|
+
obj = if options[:create_missing]
|
59
|
+
obj[key] ||= Hash.new
|
60
|
+
else
|
61
|
+
obj.has_key?(key) ? obj[key] : NotFound.new
|
62
|
+
end
|
63
|
+
|
64
|
+
get_target_member(obj, fragments, options, &block)
|
65
|
+
when Array
|
66
|
+
if fragment == WILDCARD
|
67
|
+
obj.each do |i|
|
68
|
+
get_target_member(i || Hash.new, fragments.dup, options, &block)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
index = fragment_to_index(fragment)
|
72
|
+
obj = if options[:create_missing]
|
73
|
+
obj[index] ||= Hash.new
|
74
|
+
else
|
75
|
+
index >= obj.size ? NotFound.new : obj[index]
|
76
|
+
end
|
77
|
+
|
78
|
+
get_target_member(obj, fragments, &block)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
NotFound.new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_member_value(new_value)
|
86
|
+
obj = @hash
|
87
|
+
fragments = path_fragments.dup
|
88
|
+
|
89
|
+
return if fragments.empty?
|
90
|
+
|
91
|
+
target_fragment = fragments.pop
|
92
|
+
|
93
|
+
if target_fragment == ARRAY_PUSH_KEY
|
94
|
+
target_parent_fragment = fragments.pop
|
95
|
+
end
|
96
|
+
|
97
|
+
get_target_member(obj, fragments, :create_missing => true) do |target|
|
98
|
+
if target_fragment == ARRAY_PUSH_KEY
|
99
|
+
case target
|
100
|
+
when Hash
|
101
|
+
key = fragment_to_key(target_parent_fragment)
|
102
|
+
when Array
|
103
|
+
key = fragment_to_index(target_parent_fragment)
|
104
|
+
end
|
105
|
+
|
106
|
+
target[key] ||= Array.new
|
107
|
+
if Array === target[key]
|
108
|
+
target[key].push(new_value)
|
109
|
+
return new_value
|
110
|
+
else
|
111
|
+
return
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
case target
|
116
|
+
when Hash
|
117
|
+
target[fragment_to_key(target_fragment)] = new_value
|
118
|
+
when Array
|
119
|
+
if target_fragment == WILDCARD
|
120
|
+
target.map! { new_value }
|
121
|
+
else
|
122
|
+
target.insert(fragment_to_index(target_fragment), new_value)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete_member
|
129
|
+
obj = @hash
|
130
|
+
fragments = path_fragments.dup
|
131
|
+
|
132
|
+
return if fragments.empty?
|
133
|
+
|
134
|
+
target_fragment = fragments.pop
|
135
|
+
get_target_member(obj, fragments) do |target|
|
136
|
+
case target
|
137
|
+
when Hash
|
138
|
+
target.delete(fragment_to_key(target_fragment))
|
139
|
+
when Array
|
140
|
+
if target_fragment == WILDCARD
|
141
|
+
target.replace([])
|
142
|
+
else
|
143
|
+
target.delete_at(fragment_to_index(target_fragment))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def path_fragments
|
150
|
+
@path_fragments ||= @path.sub(%r{\A/}, '').split("/").map { |fragment| unescape_fragment(fragment) }
|
151
|
+
end
|
152
|
+
|
153
|
+
def unescape_fragment(fragment)
|
154
|
+
fragment.gsub(/~1/, '/').gsub(/~0/, '~')
|
155
|
+
end
|
156
|
+
|
157
|
+
def fragment_to_key(fragment)
|
158
|
+
if @options[:symbolize_keys]
|
159
|
+
fragment.to_sym
|
160
|
+
else
|
161
|
+
fragment
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def fragment_to_index(fragment)
|
166
|
+
fragment.to_i
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
@@ -0,0 +1,303 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "json-pointer"
|
3
|
+
|
4
|
+
describe JsonPointer do
|
5
|
+
let(:hash) do
|
6
|
+
{
|
7
|
+
:water => ["river", "lake", "ocean", "pond", "everything else"],
|
8
|
+
:fire => {
|
9
|
+
:water => {
|
10
|
+
:wind => "earth"
|
11
|
+
},
|
12
|
+
:dirt => [
|
13
|
+
{ :foo => "bar", :hello => "world" },
|
14
|
+
{ :baz => "biz" }
|
15
|
+
]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:path) { "" }
|
21
|
+
let(:path_fragments) { path.split('/') }
|
22
|
+
let(:pointer) { described_class.new(hash, path, :symbolize_keys => true) }
|
23
|
+
let(:parent_pointer) {
|
24
|
+
described_class.new(hash, path_fragments[0..-2].join('/'), :symbolize_keys => true)
|
25
|
+
}
|
26
|
+
let(:expected_parent_value) {}
|
27
|
+
|
28
|
+
describe "#exists?" do
|
29
|
+
shared_examples "a checker method" do
|
30
|
+
context "when member exists" do
|
31
|
+
it "returns true" do
|
32
|
+
expect(pointer.exists?).to be_true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when member exists and is nil" do
|
37
|
+
it "returns true" do
|
38
|
+
pointer.value = nil
|
39
|
+
expect(pointer.exists?).to be_true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when member doesn't exist" do
|
44
|
+
let(:hash) { Hash.new }
|
45
|
+
|
46
|
+
it "returns false" do
|
47
|
+
expect(pointer.exists?).to be_false
|
48
|
+
expect(hash).to eq(Hash.new)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when array index" do
|
54
|
+
let(:path) { %(/water/2) }
|
55
|
+
|
56
|
+
it_behaves_like "a checker method"
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when in member of array index" do
|
60
|
+
let(:path) { %(/fire/dirt/0/hello) }
|
61
|
+
|
62
|
+
it_behaves_like "a checker method"
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when array wildcard" do
|
66
|
+
let(:path) { %(/fire/dirt/*) }
|
67
|
+
|
68
|
+
it_behaves_like "a checker method"
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when in member of array windcard" do
|
72
|
+
let(:path) { %(/fire/dirt/*/hello) }
|
73
|
+
|
74
|
+
it_behaves_like "a checker method"
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when object member" do
|
78
|
+
let(:path) { %(/fire/water/wind) }
|
79
|
+
|
80
|
+
it_behaves_like "a checker method"
|
81
|
+
|
82
|
+
context "when not existant" do
|
83
|
+
let(:path) { %(/foo) }
|
84
|
+
|
85
|
+
it "returns false" do
|
86
|
+
expect(pointer.exists?).to be_false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#value" do
|
93
|
+
shared_examples "a getter method" do
|
94
|
+
context "when member exists" do
|
95
|
+
it "returns value of referenced member" do
|
96
|
+
expect(pointer.value).to eql(expected_value)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when member doesn't exist" do
|
101
|
+
let(:hash) { Hash.new }
|
102
|
+
|
103
|
+
it "returns nil" do
|
104
|
+
expect(pointer.value).to be_nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when array index" do
|
110
|
+
let(:path) { %(/water/2) }
|
111
|
+
let(:expected_value) { hash[:water][2] }
|
112
|
+
|
113
|
+
it_behaves_like "a getter method"
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when in member of array index" do
|
117
|
+
let(:path) { %(/fire/dirt/0/hello) }
|
118
|
+
let(:expected_value) { hash[:fire][:dirt][0][:hello] }
|
119
|
+
|
120
|
+
it_behaves_like "a getter method"
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when array wildcard" do
|
124
|
+
let(:path) { %(/fire/dirt/*) }
|
125
|
+
let(:expected_value) { hash[:fire][:dirt] }
|
126
|
+
|
127
|
+
it_behaves_like "a getter method"
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when in member of array windcard" do
|
131
|
+
let(:path) { %(/fire/dirt/*/hello) }
|
132
|
+
let(:expected_value) { ["world", nil] }
|
133
|
+
|
134
|
+
it_behaves_like "a getter method"
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when object member" do
|
138
|
+
let(:path) { %(/fire/water/wind) }
|
139
|
+
let(:expected_value) { hash[:fire][:water][:wind] }
|
140
|
+
|
141
|
+
it_behaves_like "a getter method"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#value=" do
|
146
|
+
let(:asymmetric) { false }
|
147
|
+
|
148
|
+
shared_examples "a setter method" do
|
149
|
+
context "when parent member exists" do
|
150
|
+
it "sets referenced member value" do
|
151
|
+
pointer.value = value
|
152
|
+
|
153
|
+
unless asymmetric
|
154
|
+
expect(pointer.value).to eql(value)
|
155
|
+
end
|
156
|
+
|
157
|
+
if expected_parent_value
|
158
|
+
expect(parent_pointer.value).to eql(expected_parent_value)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "when parent member doesn't exist" do
|
164
|
+
let(:hash) { Hash.new }
|
165
|
+
|
166
|
+
it "sets referenced member value" do
|
167
|
+
pointer.value = value
|
168
|
+
expect(pointer.value).to eql(value)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "when array index" do
|
174
|
+
let(:path) { %(/water/2) }
|
175
|
+
let(:value) { "swamp" }
|
176
|
+
let(:expected_parent_value) { ["river", "lake", value, "ocean", "pond", "everything else"] }
|
177
|
+
|
178
|
+
it_behaves_like "a setter method"
|
179
|
+
|
180
|
+
context "when appending to array" do
|
181
|
+
let(:path) { %(/water/-) }
|
182
|
+
let(:expected_parent_value) { ["river", "lake", "ocean", "pond", "everything else", value] }
|
183
|
+
end
|
184
|
+
|
185
|
+
context "when array doesn't exist" do
|
186
|
+
let(:path) { %(/water/-) }
|
187
|
+
let(:hash) { Hash.new }
|
188
|
+
let(:expected_parent_value) { [value] }
|
189
|
+
|
190
|
+
it_behaves_like "a setter method"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "when in member of array index" do
|
195
|
+
let(:path) { %(/fire/dirt/0/biz) }
|
196
|
+
let(:value) { "baz" }
|
197
|
+
let(:expected_parent_value) { { :foo => "bar", :hello => "world", :biz => value } }
|
198
|
+
|
199
|
+
it_behaves_like "a setter method"
|
200
|
+
end
|
201
|
+
|
202
|
+
context "when array wildcard" do
|
203
|
+
let(:path) { %(/water/*) }
|
204
|
+
let(:value) { "baz" }
|
205
|
+
let(:asymmetric) { true }
|
206
|
+
let(:expected_parent_value) { [value, value, value, value, value] }
|
207
|
+
|
208
|
+
it_behaves_like "a setter method"
|
209
|
+
end
|
210
|
+
|
211
|
+
context "when in member of array windcard" do
|
212
|
+
let(:path) { %(/fire/dirt/*/gash) }
|
213
|
+
let(:value) { "very deep!" }
|
214
|
+
let(:asymmetric) { true }
|
215
|
+
let(:expected_parent_value) {
|
216
|
+
[
|
217
|
+
{ :gash => value, :foo => "bar", :hello => "world" },
|
218
|
+
{ :gash => value, :baz => "biz" }
|
219
|
+
]
|
220
|
+
}
|
221
|
+
|
222
|
+
it_behaves_like "a setter method"
|
223
|
+
end
|
224
|
+
|
225
|
+
context "when object member" do
|
226
|
+
let(:path) { %(fire/water/foo) }
|
227
|
+
let(:value) { "Foo Bar!" }
|
228
|
+
|
229
|
+
it_behaves_like "a setter method"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "#delete" do
|
234
|
+
let(:asymmetric) { false }
|
235
|
+
|
236
|
+
shared_examples "a delete method" do
|
237
|
+
context "when parent member exists" do
|
238
|
+
it "deletes referenced member" do
|
239
|
+
pointer.delete
|
240
|
+
|
241
|
+
unless asymmetric
|
242
|
+
expect(pointer.value).to be_nil
|
243
|
+
end
|
244
|
+
|
245
|
+
if expected_parent_value
|
246
|
+
expect(parent_pointer.value).to eql(expected_parent_value)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
context "when parent member doesn't exist" do
|
252
|
+
let(:hash) { Hash.new }
|
253
|
+
|
254
|
+
it "does nothing" do
|
255
|
+
pointer.delete
|
256
|
+
expect(pointer.value).to be_nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context "when array index" do
|
262
|
+
let(:path) { %(/water/2) }
|
263
|
+
let(:asymmetric) { true }
|
264
|
+
let(:expected_parent_value) { ["river", "lake", "pond", "everything else"] }
|
265
|
+
|
266
|
+
it_behaves_like "a delete method"
|
267
|
+
end
|
268
|
+
|
269
|
+
context "when in member of array index" do
|
270
|
+
let(:path) { %(/fire/dirt/0/foo) }
|
271
|
+
let(:expected_parent_value) { { :hello => "world" } }
|
272
|
+
|
273
|
+
it_behaves_like "a delete method"
|
274
|
+
end
|
275
|
+
|
276
|
+
context "when array wildcard" do
|
277
|
+
let(:path) { %(/water/*) }
|
278
|
+
let(:asymmetric) { true }
|
279
|
+
let(:expected_parent_value) { [] }
|
280
|
+
|
281
|
+
it_behaves_like "a delete method"
|
282
|
+
end
|
283
|
+
|
284
|
+
context "when in member of array windcard" do
|
285
|
+
let(:path) { %(/fire/dirt/*/foo) }
|
286
|
+
let(:asymmetric) { true }
|
287
|
+
let(:expected_parent_value) {
|
288
|
+
[
|
289
|
+
{ :hello => "world" },
|
290
|
+
{ :baz => "biz" }
|
291
|
+
]
|
292
|
+
}
|
293
|
+
|
294
|
+
it_behaves_like "a delete method"
|
295
|
+
end
|
296
|
+
|
297
|
+
context "when object member" do
|
298
|
+
let(:path) { %(fire/water/foo) }
|
299
|
+
|
300
|
+
it_behaves_like "a delete method"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-pointer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jesse Stuart
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.11'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.11'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: JSON Pointer implementation
|
47
|
+
email:
|
48
|
+
- jesse@jessestuart.ca
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- json-pointer.gemspec
|
59
|
+
- lib/json-pointer.rb
|
60
|
+
- lib/json-pointer/version.rb
|
61
|
+
- spec/json_pointer_spec.rb
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
homepage: ''
|
64
|
+
licenses: []
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ! '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.8.23
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: JSON Pointer implementation
|
87
|
+
test_files:
|
88
|
+
- spec/json_pointer_spec.rb
|
89
|
+
- spec/spec_helper.rb
|