Skip to content

Instantly share code, notes, and snippets.

@cabo
Created December 10, 2013 10:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cabo/7888768 to your computer and use it in GitHub Desktop.
Save cabo/7888768 to your computer and use it in GitHub Desktop.
JSON Merge-Patch examples: A simple implementation of json merge-patch (http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch/). Code to extract the examples from the draft helps see the difference that eliding purge_nulls makes. Because of recent changes to JSON (non-containers at top level), requires "oj" gem.
Let's see where we don't agree (this code doesn't do purge_nulls):
Mismatch:
orig: {"a":"foo","b":[3,null,{"x":null}]}
patch: {"b":[3,null,{"x":null}]}
draft: {"a":"foo","b":[3,{}]}
actual: {"a":"foo","b":[3,null,{"x":null}]}
Mismatch:
orig: [1,2]
patch: [1,null,3]
draft: [1,3]
actual: [1,null,3]
Mismatch:
orig: [1,2]
patch: [1,null,2]
draft: [1,2]
actual: [1,null,2]
Mismatch:
orig: {"a":[{"z":1,"b":null}]}
patch: {"a":[{"z":1,"b":null}]}
draft: {"a":[{"z":1}]}
actual: {"a":[{"z":1,"b":null}]}
Mismatch:
orig: {"a":"foo"}
patch: null
draft: "Invalid Example"
actual: null
Mismatch:
orig: {"a":"foo"}
patch: "bar"
draft: "Invalid Example"
actual: "bar"
def merge_patch(orig, patch)
if Hash === patch
orig = {} unless Hash === orig
patch.each do |k, v|
if v.nil?
orig.delete(k)
else
orig[k] = merge_patch(orig[k], v)
end
end
orig
else
patch
end
end # yep, that's 15 lines.
data = DATA.read.lines.map(&:chomp)
cols = data.shift.scan(/\w*\s+/).map(&:size)
data.shift # discard ---
examples = [["", "", ""]]
data.each { |line|
s = cols.map { |c| line.slice!(0, c) } << line
if s.shift == ""
examples << ["", "", ""]
else
examples.last.each_with_index do |ex, i|
ex << s[i].strip
end
end
}
require 'oj' # this json does non-containers
triples = examples.map do |ex|
ex.map {|s| Oj.load(s) rescue "Invalid Example"}
end
puts "Let's see where we don't agree (this code doesn't do purge_nulls):"
triples.each do |o, p, r|
res = merge_patch(o, p)
if r != res
puts "Mismatch: "
puts "orig: #{Oj.dump(o)}"
puts "patch: #{Oj.dump(p)}"
puts "draft: #{Oj.dump(r)}"
puts "actual: #{Oj.dump(res)}"
end
end
__END__
ORIGINAL PATCH RESULT
------------------------------------------
{"a":"b"} {"a":"c"} {"a":"c"}
{"a":"b"} {"b":"c"} {"a":"b",
"b":"c"}
{"a":"b"} {"a":null} {}
{"a":"b", {"a":null} {"b":"c"}
"b":"c"}
{"a":["b"]} {"a":"c"} {"a":"c"}
{"a":"c"} {"a":["b"]} {"a":["b"]}
{"a": { {"a": { {"a": {
"b": "c"} "b": "d", "b": "d"
} "c": null} }
} }
{"a": [ {"a": [1]} {"a": [1]}
{"b":"c"}
]
}
["a","b"] ["c","d"] ["c","d"]
{"a":"b"} ["c"] ["c"]
[1,2] {"a":"b", {"a":"b"}
"c":null}
{"e":null} {"a":1} {"e":null,
"a":1}
{} {"a": { {"a": {
"bb": { "bb": {
"ccc":null }}}
}}}
{"a":"foo"} {"b": [ {"a":"foo",
3, "b": [3, {}]
null, }
{"x":null}
]
}
[1,2] [1,null,3] [1,3]
[1,2] [1,null,2] [1,2]
{"a":"b"} {"a": [ {"a": [
{"z":1, {"z":1}
"b":null ]
} }
]
}
{"a":"foo"} null Invalid Patch
{"a":"foo"} "bar" Invalid Patch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment