json-merge_patch 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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +78 -0
- data/Rakefile +11 -0
- data/json-merge_patch.gemspec +24 -0
- data/lib/json/merge_patch.rb +27 -0
- data/lib/json/merge_patch/version.rb +5 -0
- data/test/merge_patch_test.rb +179 -0
- data/test/test_helper.rb +17 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bda345671285245e45dc0666b0ce0e79c15d3950
|
4
|
+
data.tar.gz: c1b5cd2284d269260896ff5be37e1eda7eba05b9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 19dc0616daa81fa8d9b8de3db0b496a2447ee81325e0a786fca1468ad03c63f9a30e2d733bc4ff4fdc3994d87cfe4bd46119eaa3e33a4315001af47dcb8f0755
|
7
|
+
data.tar.gz: 60c56930ed226e38e7d7fd5199f3f2e85ff97220a325c2f29e4660f8fd31929e1daa91be87dfbe4e021ce080fe7d30645705ee385e67c7b07acc5769f229993d
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Steve Klabnik
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Json::MergePatch
|
2
|
+
|
3
|
+
[](https://travis-ci.org/steveklabnik/json-merge_patch)
|
4
|
+
|
5
|
+
This gem augments Ruby's built-in JSON library to support merging JSON blobs
|
6
|
+
in accordance with the [draft-snell-merge-patch
|
7
|
+
draft](http://tools.ietf.org/html/draft-snell-merge-patch-08).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'json-merge_patch'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install json-merge_patch
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
First, require the gem:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'json/merge_patch'
|
29
|
+
```
|
30
|
+
|
31
|
+
Then, use it:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
# The example from http://tools.ietf.org/html/draft-snell-merge-patch-08#section-2
|
35
|
+
|
36
|
+
document = <<-JSON
|
37
|
+
{
|
38
|
+
"title": "Goodbye!",
|
39
|
+
"author" : {
|
40
|
+
"givenName" : "John",
|
41
|
+
"familyName" : "Doe"
|
42
|
+
},
|
43
|
+
"tags":["example","sample"],
|
44
|
+
"content": "This will be unchanged"
|
45
|
+
}
|
46
|
+
JSON
|
47
|
+
|
48
|
+
merge_patch = <<-JSON
|
49
|
+
{
|
50
|
+
"title": "Hello!",
|
51
|
+
"phoneNumber": "+01-123-456-7890",
|
52
|
+
"author": {
|
53
|
+
"familyName": null
|
54
|
+
},
|
55
|
+
"tags": ["example"]
|
56
|
+
}
|
57
|
+
JSON
|
58
|
+
|
59
|
+
JSON.merge(document, merge_patch)
|
60
|
+
# =>
|
61
|
+
{
|
62
|
+
"title": "Goodbye!",
|
63
|
+
"author" : {
|
64
|
+
"phoneNumber": "+01-123-456-7890",
|
65
|
+
"givenName" : "John",
|
66
|
+
},
|
67
|
+
"tags":["example"],
|
68
|
+
"content": "This will be unchanged"
|
69
|
+
}
|
70
|
+
```
|
71
|
+
|
72
|
+
## Contributing
|
73
|
+
|
74
|
+
1. Fork it
|
75
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
76
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
77
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
78
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'json/merge_patch/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "json-merge_patch"
|
8
|
+
spec.version = Json::MergePatch::VERSION
|
9
|
+
spec.authors = ["Steve Klabnik"]
|
10
|
+
spec.email = ["steve@steveklabnik.com"]
|
11
|
+
spec.description = %q{An implementation of the json-merge-patch draft.}
|
12
|
+
spec.summary = %q{An implementation of the json-merge-patch draft.}
|
13
|
+
spec.homepage = "https://github.com/steveklabnik/json-merge_patch"
|
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.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "minitest"
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'json'
|
2
|
+
require "json/merge_patch/version"
|
3
|
+
|
4
|
+
module JSON
|
5
|
+
MergeError = Class.new(StandardError)
|
6
|
+
|
7
|
+
def self.merge(document, merge_patch)
|
8
|
+
document = JSON.parse(document)
|
9
|
+
merge_patch = JSON.parse(merge_patch)
|
10
|
+
|
11
|
+
if merge_patch.is_a? Array
|
12
|
+
return JSON.dump(merge_patch)
|
13
|
+
end
|
14
|
+
|
15
|
+
if document.is_a? Array
|
16
|
+
return JSON.dump(merge_patch)
|
17
|
+
end
|
18
|
+
|
19
|
+
if merge_patch.is_a? Hash
|
20
|
+
document.merge!(merge_patch)
|
21
|
+
document.delete_if {|k, v| v.nil? }
|
22
|
+
return JSON.dump(document)
|
23
|
+
end
|
24
|
+
rescue
|
25
|
+
raise MergeError
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'json/merge_patch'
|
4
|
+
|
5
|
+
describe "Section 1" do
|
6
|
+
=begin
|
7
|
+
1. If either the root of the JSON data provided in the payload or
|
8
|
+
the root of the target resource are JSON Arrays, the target
|
9
|
+
resource is to be replaced, in whole, by the provided data. Any
|
10
|
+
object member contained in the provided data whose value is
|
11
|
+
explicitly null is to be treated as if the member was undefined.
|
12
|
+
=end
|
13
|
+
|
14
|
+
describe "if the root of the data provided is an array" do
|
15
|
+
let(:merge_patch) { %q'["foo"]' }
|
16
|
+
|
17
|
+
it "replaces the root whole" do
|
18
|
+
document = %q'{"foo":"bar"}'
|
19
|
+
|
20
|
+
expected = %q'["foo"]'
|
21
|
+
|
22
|
+
assert_equal expected, JSON.merge(document, merge_patch)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "if the root of the target resource is an array" do
|
27
|
+
let(:document) { %q'["foo"]' }
|
28
|
+
|
29
|
+
it "replaces the root whole" do
|
30
|
+
merge_patch = %q'{"foo":"bar"}'
|
31
|
+
|
32
|
+
expected = %q'{"foo":"bar"}'
|
33
|
+
|
34
|
+
assert_equal expected, JSON.merge(document, merge_patch)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "section 2" do
|
40
|
+
=begin
|
41
|
+
2. If the root of the JSON data provided in the payload is an
|
42
|
+
Object, for each distinct member specified within that object:
|
43
|
+
=end
|
44
|
+
|
45
|
+
describe "part 1" do
|
46
|
+
=begin
|
47
|
+
* If the member is currently undefined within the target
|
48
|
+
resource, and the given value is not null, the member and the
|
49
|
+
value are to be added to the target. Any object member
|
50
|
+
contained in the provided data whose value is explicitly null
|
51
|
+
is to be treated as if the member were undefined.
|
52
|
+
=end
|
53
|
+
it "adds members" do
|
54
|
+
document = %q'{"foo":"bar"}'
|
55
|
+
|
56
|
+
merge_patch = %q'{"foo":"bar","baz":"quxx"}'
|
57
|
+
|
58
|
+
expected = %q'{"foo":"bar","baz":"quxx"}'
|
59
|
+
|
60
|
+
assert_equal expected, JSON.merge(document, merge_patch)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "part 2" do
|
65
|
+
=begin
|
66
|
+
* If the value is explicitly set to null and that member is
|
67
|
+
currently defined within the target resource, the existing
|
68
|
+
member is removed.
|
69
|
+
=end
|
70
|
+
it "removes members" do
|
71
|
+
document = %q'{"foo":"bar"}'
|
72
|
+
|
73
|
+
merge_patch = %q'{"foo":null}'
|
74
|
+
|
75
|
+
expected = %q'{}'
|
76
|
+
|
77
|
+
assert_equal expected, JSON.merge(document, merge_patch)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "part 3" do
|
82
|
+
=begin
|
83
|
+
* If the value is either a non-null JSON primitive or an Array
|
84
|
+
and that member is currently defined within the target
|
85
|
+
resource, the existing value for that member is to be replaced
|
86
|
+
with that provided. Any object member contained in the
|
87
|
+
provided data whose value is explicitly null is to be treated
|
88
|
+
as if the member were undefined.
|
89
|
+
=end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "part 4" do
|
93
|
+
=begin
|
94
|
+
* If the value is a JSON object and that member is currently
|
95
|
+
defined for the target resource and the existing value is a
|
96
|
+
JSON primitive or Array, the existing value is to be replaced
|
97
|
+
in whole by the object provided. Any object member contained
|
98
|
+
in the provided data whose value is explicitly null is to be
|
99
|
+
treated as if the member was undefined.
|
100
|
+
=end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "part 5" do
|
104
|
+
=begin
|
105
|
+
* If the value is a JSON object and that member is currently
|
106
|
+
defined within the target resource and the existing value is
|
107
|
+
also a JSON object, then recursively apply Rule #2 to each
|
108
|
+
object.
|
109
|
+
=end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "part 6" do
|
113
|
+
=begin
|
114
|
+
* Any member currently defined within the target resource that
|
115
|
+
does not explicitly appear within the patch is to remain
|
116
|
+
untouched and unmodified.
|
117
|
+
=end
|
118
|
+
it "leaves well enough alone!" do
|
119
|
+
document = %q'{"content": "This will be unchanged"}'
|
120
|
+
|
121
|
+
merge_patch = %q'{}'
|
122
|
+
|
123
|
+
expected = %q'{"content":"This will be unchanged"}'
|
124
|
+
|
125
|
+
assert_equal expected, JSON.merge(document, merge_patch)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "README example" do
|
131
|
+
it "works properly" do
|
132
|
+
document = <<-JSON.strip_heredoc.chomp
|
133
|
+
{
|
134
|
+
"title": "Goodbye!",
|
135
|
+
"author" : {
|
136
|
+
"givenName" : "John",
|
137
|
+
"familyName" : "Doe"
|
138
|
+
},
|
139
|
+
"tags":["example","sample"],
|
140
|
+
"content": "This will be unchanged"
|
141
|
+
}
|
142
|
+
JSON
|
143
|
+
|
144
|
+
merge_patch = <<-JSON.strip_heredoc.chomp
|
145
|
+
{
|
146
|
+
"title": "Hello!",
|
147
|
+
"phoneNumber": "+01-123-456-7890",
|
148
|
+
"author": {
|
149
|
+
"familyName": null
|
150
|
+
},
|
151
|
+
"tags": ["example"]
|
152
|
+
}
|
153
|
+
JSON
|
154
|
+
|
155
|
+
expected = <<-JSON.strip_heredoc.chomp
|
156
|
+
{
|
157
|
+
"title": "Goodbye!",
|
158
|
+
"author" : {
|
159
|
+
"phoneNumber": "+01-123-456-7890",
|
160
|
+
"givenName" : "John",
|
161
|
+
},
|
162
|
+
"tags":["example"],
|
163
|
+
"content": "This will be unchanged"
|
164
|
+
}
|
165
|
+
JSON
|
166
|
+
|
167
|
+
pending do
|
168
|
+
assert_equal expected, JSON.merge(document, merge_patch)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "errors" do
|
174
|
+
it "throws an error when stuff goes wrong" do
|
175
|
+
assert_raises(JSON::MergeError) do
|
176
|
+
JSON.merge(nil, nil)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
def pending
|
4
|
+
begin
|
5
|
+
yield
|
6
|
+
fail "OMG pending test passed."
|
7
|
+
rescue MiniTest::Assertion
|
8
|
+
skip "Still pending"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class String
|
13
|
+
def strip_heredoc
|
14
|
+
indent = scan(/^[ \t]*(?=\S)/).min.send(:size) || 0
|
15
|
+
gsub(/^[ \t]{#{indent}}/, '')
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-merge_patch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steve Klabnik
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-13 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.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
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: minitest
|
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
|
+
description: An implementation of the json-merge-patch draft.
|
56
|
+
email:
|
57
|
+
- steve@steveklabnik.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .travis.yml
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- json-merge_patch.gemspec
|
69
|
+
- lib/json/merge_patch.rb
|
70
|
+
- lib/json/merge_patch/version.rb
|
71
|
+
- test/merge_patch_test.rb
|
72
|
+
- test/test_helper.rb
|
73
|
+
homepage: https://github.com/steveklabnik/json-merge_patch
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.0.0
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: An implementation of the json-merge-patch draft.
|
97
|
+
test_files:
|
98
|
+
- test/merge_patch_test.rb
|
99
|
+
- test/test_helper.rb
|
100
|
+
has_rdoc:
|