object_patch 0.8.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.gitmodules +4 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/.yardopts +3 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +77 -0
- data/Rakefile +18 -0
- data/TODO.md +7 -0
- data/lib/object_patch.rb +46 -0
- data/lib/object_patch/exceptions.rb +51 -0
- data/lib/object_patch/generator.rb +114 -0
- data/lib/object_patch/operation_factory.rb +25 -0
- data/lib/object_patch/operations.rb +79 -0
- data/lib/object_patch/operations/add.rb +57 -0
- data/lib/object_patch/operations/copy.rb +69 -0
- data/lib/object_patch/operations/move.rb +63 -0
- data/lib/object_patch/operations/remove.rb +49 -0
- data/lib/object_patch/operations/replace.rb +59 -0
- data/lib/object_patch/operations/test.rb +47 -0
- data/lib/object_patch/pointer.rb +90 -0
- data/lib/object_patch/version.rb +4 -0
- data/object_patch.gemspec +28 -0
- data/spec/fixtures/tenderlove_tests.json +36 -0
- data/spec/helpers/json_test_loader.rb +19 -0
- data/spec/object_patch/fixture_tests_spec.rb +62 -0
- data/spec/object_patch/object_patch_spec.rb +9 -0
- data/spec/object_patch/pointer_spec.rb +52 -0
- data/spec/spec_helper.rb +24 -0
- metadata +181 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'object_patch/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "object_patch"
|
8
|
+
spec.version = ObjectPatch::VERSION
|
9
|
+
spec.authors = ["Sam Stelfox"]
|
10
|
+
spec.email = ["sstelfox+gh@bedroomprogrammers.net"]
|
11
|
+
spec.description = %q{An implementation of JSON::Patch but for hashes and array. The results can be converted to JSON using the standard JSON library and the result will be a valid JSON::Patch.}
|
12
|
+
spec.summary = %q{An implementation of JSON::Patch but for hashes and array.}
|
13
|
+
spec.homepage = "http://stelfox.net/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.2"
|
22
|
+
spec.add_development_dependency "coveralls"
|
23
|
+
spec.add_development_dependency "pry"
|
24
|
+
spec.add_development_dependency "simplecov"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "yard"
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
[
|
2
|
+
{ "comment": "test remove with bad number should fail",
|
3
|
+
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
|
4
|
+
"patch": [{"op": "remove", "path": "/baz/1e0/qux"}],
|
5
|
+
"error": "remove op shouldn't remove from array with bad number" },
|
6
|
+
|
7
|
+
{ "comment": "test remove on array",
|
8
|
+
"doc": [1, 2, 3, 4],
|
9
|
+
"patch": [{"op": "remove", "path": "/0"}],
|
10
|
+
"expected": [2, 3, 4] },
|
11
|
+
|
12
|
+
{ "comment": "test remove with bad index should fail",
|
13
|
+
"doc": [1, 2, 3, 4],
|
14
|
+
"patch": [{"op": "remove", "path": "/1e0"}],
|
15
|
+
"error": "remove op shouldn't remove from array with bad number" },
|
16
|
+
|
17
|
+
{ "comment": "test replace with bad number should fail",
|
18
|
+
"doc": [""],
|
19
|
+
"patch": [{"op": "replace", "path": "/1e0", "value": false}],
|
20
|
+
"error": "replace op shouldn't replace in array with bad number" },
|
21
|
+
|
22
|
+
{ "comment": "test copy with bad number should fail",
|
23
|
+
"doc": {"baz": [1,2,3], "bar": 1},
|
24
|
+
"patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}],
|
25
|
+
"error": "copy op shouldn't work with bad number" },
|
26
|
+
|
27
|
+
{ "comment": "test move with bad number should fail",
|
28
|
+
"doc": {"foo": 1, "baz": [1,2,3,4]},
|
29
|
+
"patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}],
|
30
|
+
"error": "move op shouldn't work with bad number" },
|
31
|
+
|
32
|
+
{ "comment": "test add with bad number should fail",
|
33
|
+
"doc": ["foo", "sil"],
|
34
|
+
"patch": [{"op": "add", "path": "/1e0", "value": "bar"}],
|
35
|
+
"error": "add op shouldn't add to array with bad number" }
|
36
|
+
]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
TEST_DIR = File.expand_path('../../', __FILE__)
|
5
|
+
|
6
|
+
module JSONTestLoader
|
7
|
+
# Load a JSON test file for auto generation of tests based on IETF tests, my
|
8
|
+
# own, and some from tenderlove.
|
9
|
+
#
|
10
|
+
# @param [String] path Path to the fixture from root of the fixtures
|
11
|
+
# directory, should not have a path at the beginning or the end.
|
12
|
+
# @return [Array<Hash>] The tests
|
13
|
+
def load_file(path)
|
14
|
+
JSON.parse(File.read(File.join(TEST_DIR, 'fixtures', path)))
|
15
|
+
end
|
16
|
+
|
17
|
+
module_function :load_file
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
require 'spec_helper'
|
3
|
+
BaseException = Class.new(StandardError)
|
4
|
+
|
5
|
+
# InvalidIndexError
|
6
|
+
# InvalidOperation
|
7
|
+
# MissingTargetException
|
8
|
+
# ObjectOperationOnArrayException
|
9
|
+
# OutOfBoundsException
|
10
|
+
# TraverseScalarException
|
11
|
+
# FailedTestException
|
12
|
+
|
13
|
+
def msg_to_exception(msg)
|
14
|
+
case msg
|
15
|
+
when /out of bounds/i; ObjectPatch::InvalidIndexError
|
16
|
+
when /missing|non-existant/; ObjectPatch::MissingTargetException
|
17
|
+
else; [ObjectPatch::InvalidIndexError, ObjectPatch::FailedTestException]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_test(t)
|
22
|
+
# Even the disabled tests are passing now...
|
23
|
+
#pending "Disabled: #{t["comment"]}" if t["disabled"]
|
24
|
+
|
25
|
+
!!t['error'] ? test_for_error(t) : test_success(t)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_for_error(t)
|
29
|
+
it t["comment"] do
|
30
|
+
excep = msg_to_exception(t["error"])
|
31
|
+
patch = t["patch"]
|
32
|
+
source_hash = t["doc"]
|
33
|
+
|
34
|
+
expect { ObjectPatch.apply(source_hash, patch) }.to raise_error { |e| Array(msg_to_exception(t["error"])).include?(e) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_success(t)
|
39
|
+
task_name = t["comment"] || t["patch"]
|
40
|
+
|
41
|
+
if t['expected']
|
42
|
+
it task_name do
|
43
|
+
source_hash = t["doc"]
|
44
|
+
patch = t["patch"]
|
45
|
+
|
46
|
+
ObjectPatch.apply(source_hash, patch).should eq(t['expected'])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
it "#{task_name} should not raise error" do
|
50
|
+
source_hash = t["doc"]
|
51
|
+
patch = t["patch"]
|
52
|
+
|
53
|
+
expect { ObjectPatch.apply(source_hash, patch) }.to_not raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ObjectPatch do
|
59
|
+
JSONTestLoader.load_file('json-patch-tests/spec_tests.json').each { |t| run_test(t) }
|
60
|
+
JSONTestLoader.load_file('json-patch-tests/tests.json').each { |t| run_test(t) }
|
61
|
+
JSONTestLoader.load_file('tenderlove_tests.json').each { |t| run_test(t) }
|
62
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ObjectPatch::Pointer do
|
5
|
+
conversions = [
|
6
|
+
[ [''], '/' ],
|
7
|
+
[ ['a/b'], '/a~1b' ],
|
8
|
+
[ ['c%d'], '/c%d' ],
|
9
|
+
[ ['e^f'], '/e^f' ],
|
10
|
+
[ ['g|h'], '/g|h' ],
|
11
|
+
[ ['i\\j'], '/i\\j' ],
|
12
|
+
[ ['k\"l'], '/k\"l' ],
|
13
|
+
[ [' '], '/ ' ],
|
14
|
+
[ ['m~n'], '/m~0n' ],
|
15
|
+
[ ['test', '1'], '/test/1' ],
|
16
|
+
]
|
17
|
+
|
18
|
+
conversions.each do |c|
|
19
|
+
it "should encode #{c.first} as #{c.last}" do
|
20
|
+
ObjectPatch::Pointer.encode(c.first).should eq(c.last)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should decode #{c.last} as #{c.first}" do
|
24
|
+
ObjectPatch::Pointer.parse(c.last).should eq(c.first)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "#escape" do
|
29
|
+
it "should escape ~ as ~0" do
|
30
|
+
ObjectPatch::Pointer.escape("~").should eq("~0")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should escape / as ~1" do
|
34
|
+
ObjectPatch::Pointer.escape("/").should eq("~1")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "#unescape" do
|
39
|
+
it "should unescape ~0 as ~" do
|
40
|
+
ObjectPatch::Pointer.unescape("~0").should eq("~")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should unescape ~1 as /" do
|
44
|
+
ObjectPatch::Pointer.unescape("~1").should eq("/")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should unescape ~s before /s to prevent double unrolling" do
|
48
|
+
ObjectPatch::Pointer.unescape("~01").should eq("~1")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
|
4
|
+
require 'coveralls'
|
5
|
+
require 'simplecov'
|
6
|
+
|
7
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
8
|
+
SimpleCov::Formatter::HTMLFormatter,
|
9
|
+
Coveralls::SimpleCov::Formatter
|
10
|
+
]
|
11
|
+
SimpleCov.start
|
12
|
+
|
13
|
+
require 'object_patch'
|
14
|
+
require 'helpers/json_test_loader'
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
18
|
+
config.run_all_when_everything_filtered = true
|
19
|
+
config.filter_run :focus
|
20
|
+
config.order = 'random'
|
21
|
+
|
22
|
+
config.include JSONTestLoader
|
23
|
+
end
|
24
|
+
|
metadata
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: object_patch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Stelfox
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: coveralls
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: An implementation of JSON::Patch but for hashes and array. The results
|
112
|
+
can be converted to JSON using the standard JSON library and the result will be
|
113
|
+
a valid JSON::Patch.
|
114
|
+
email:
|
115
|
+
- sstelfox+gh@bedroomprogrammers.net
|
116
|
+
executables: []
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- .gitignore
|
121
|
+
- .gitmodules
|
122
|
+
- .rspec
|
123
|
+
- .travis.yml
|
124
|
+
- .yardopts
|
125
|
+
- Gemfile
|
126
|
+
- LICENSE.txt
|
127
|
+
- README.md
|
128
|
+
- Rakefile
|
129
|
+
- TODO.md
|
130
|
+
- lib/object_patch.rb
|
131
|
+
- lib/object_patch/exceptions.rb
|
132
|
+
- lib/object_patch/generator.rb
|
133
|
+
- lib/object_patch/operation_factory.rb
|
134
|
+
- lib/object_patch/operations.rb
|
135
|
+
- lib/object_patch/operations/add.rb
|
136
|
+
- lib/object_patch/operations/copy.rb
|
137
|
+
- lib/object_patch/operations/move.rb
|
138
|
+
- lib/object_patch/operations/remove.rb
|
139
|
+
- lib/object_patch/operations/replace.rb
|
140
|
+
- lib/object_patch/operations/test.rb
|
141
|
+
- lib/object_patch/pointer.rb
|
142
|
+
- lib/object_patch/version.rb
|
143
|
+
- object_patch.gemspec
|
144
|
+
- spec/fixtures/tenderlove_tests.json
|
145
|
+
- spec/helpers/json_test_loader.rb
|
146
|
+
- spec/object_patch/fixture_tests_spec.rb
|
147
|
+
- spec/object_patch/object_patch_spec.rb
|
148
|
+
- spec/object_patch/pointer_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
homepage: http://stelfox.net/
|
151
|
+
licenses:
|
152
|
+
- MIT
|
153
|
+
metadata: {}
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options: []
|
156
|
+
require_paths:
|
157
|
+
- lib
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
requirements: []
|
169
|
+
rubyforge_project:
|
170
|
+
rubygems_version: 2.0.7
|
171
|
+
signing_key:
|
172
|
+
specification_version: 4
|
173
|
+
summary: An implementation of JSON::Patch but for hashes and array.
|
174
|
+
test_files:
|
175
|
+
- spec/fixtures/tenderlove_tests.json
|
176
|
+
- spec/helpers/json_test_loader.rb
|
177
|
+
- spec/object_patch/fixture_tests_spec.rb
|
178
|
+
- spec/object_patch/object_patch_spec.rb
|
179
|
+
- spec/object_patch/pointer_spec.rb
|
180
|
+
- spec/spec_helper.rb
|
181
|
+
has_rdoc:
|