hana-1.3.6/0000755000175000017500000000000013724225353011462 5ustar pravipravihana-1.3.6/lib/0000755000175000017500000000000013724225353012230 5ustar pravipravihana-1.3.6/lib/hana.rb0000644000175000017500000001215213724225353013465 0ustar pravipravi# frozen_string_literal: true module Hana VERSION = '1.3.6' class Pointer include Enumerable class Exception < StandardError end class FormatError < Exception end def initialize path @path = Pointer.parse path end def each(&block); @path.each(&block); end def eval object Pointer.eval @path, object end ESC = {'^/' => '/', '^^' => '^', '~0' => '~', '~1' => '/'} # :nodoc: def self.eval list, object list.inject(object) { |o, part| return nil unless o if Array === o raise Patch::IndexError unless part =~ /\A(?:\d|[1-9]\d+)\Z/ part = part.to_i end o[part] } end def self.parse path return [''] if path == '/' return [] if path == '' unless path.start_with? '/' raise FormatError, "JSON Pointer should start with a slash" end parts = path.sub(/^\//, '').split(/(? e raise Hana::Patch::MissingTargetException, e.message end end add_op dest, key, obj doc end def test ins, doc expected = Pointer.new(ins[PATH]).eval doc unless expected == ins.fetch(VALUE) raise FailedTestException.new(ins[VALUE], ins[PATH]) end doc end def replace ins, doc list = Pointer.parse ins[PATH] key = list.pop obj = Pointer.eval list, doc return ins.fetch VALUE unless key if Array === obj raise Patch::IndexError unless key =~ /\A\d+\Z/ obj[key.to_i] = ins.fetch VALUE else raise Patch::MissingTargetException unless obj obj[key] = ins.fetch VALUE end doc end def remove ins, doc list = Pointer.parse ins[PATH] key = list.pop obj = Pointer.eval list, doc rm_op obj, key doc end def check_index obj, key return -1 if key == '-' raise ObjectOperationOnArrayException unless key =~ /\A-?\d+\Z/ idx = key.to_i raise OutOfBoundsException if idx > obj.length || idx < 0 idx end def add_op dest, key, obj if Array === dest dest.insert check_index(dest, key), obj else dest[key] = obj end end def rm_op obj, key if Array === obj raise Patch::IndexError unless key =~ /\A\d+\Z/ key = key.to_i raise Patch::OutOfBoundsException if key >= obj.length obj.delete_at key else raise Patch::IndexError unless obj&.key? key obj.delete key end end end end hana-1.3.6/README.md0000644000175000017500000000332513724225353012744 0ustar pravipravi# hana * http://github.com/tenderlove/hana ## DESCRIPTION: Implementation of [JSON Patch][1] and [JSON Pointer][2] RFC. ## FEATURES/PROBLEMS: Implements specs of the [JSON Patch][1] and [JSON pointer][2] RFCs: This works against Ruby objects, so you should load the JSON to Ruby, process it, then emit as JSON again. ## SYNOPSIS: ```ruby patch = Hana::Patch.new [ { 'op' => 'add', 'path' => '/baz', 'value' => 'qux' } ] patch.apply('foo' => 'bar') # => {'baz' => 'qux', 'foo' => 'bar'} ``` ## REQUIREMENTS: * Ruby ## INSTALL: $ gem install hana ## LICENSE: (The MIT License) Copyright (c) 2012-2016 Aaron Patterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [1]: https://datatracker.ietf.org/doc/rfc6902/ [2]: http://tools.ietf.org/html/rfc6901 hana-1.3.6/Manifest.txt0000644000175000017500000000047513724225353013777 0ustar pravipraviManifest.txt README.md Rakefile lib/hana.rb test/helper.rb test/json-patch-tests/.editorconfig test/json-patch-tests/.npmignore test/json-patch-tests/README.md test/json-patch-tests/package.json test/json-patch-tests/spec_tests.json test/json-patch-tests/tests.json test/mine.json test/test_hana.rb test/test_ietf.rb hana-1.3.6/test/0000755000175000017500000000000013724225353012441 5ustar pravipravihana-1.3.6/test/json-patch-tests/0000755000175000017500000000000013724225353015647 5ustar pravipravihana-1.3.6/test/json-patch-tests/tests.json0000644000175000017500000004304413724225353017711 0ustar pravipravi[ { "comment": "empty list, empty docs", "doc": {}, "patch": [], "expected": {} }, { "comment": "empty patch list", "doc": {"foo": 1}, "patch": [], "expected": {"foo": 1} }, { "comment": "rearrangements OK?", "doc": {"foo": 1, "bar": 2}, "patch": [], "expected": {"bar":2, "foo": 1} }, { "comment": "rearrangements OK? How about one level down ... array", "doc": [{"foo": 1, "bar": 2}], "patch": [], "expected": [{"bar":2, "foo": 1}] }, { "comment": "rearrangements OK? How about one level down...", "doc": {"foo":{"foo": 1, "bar": 2}}, "patch": [], "expected": {"foo":{"bar":2, "foo": 1}} }, { "comment": "add replaces any existing field", "doc": {"foo": null}, "patch": [{"op": "add", "path": "/foo", "value":1}], "expected": {"foo": 1} }, { "comment": "toplevel array", "doc": [], "patch": [{"op": "add", "path": "/0", "value": "foo"}], "expected": ["foo"] }, { "comment": "toplevel array, no change", "doc": ["foo"], "patch": [], "expected": ["foo"] }, { "comment": "toplevel object, numeric string", "doc": {}, "patch": [{"op": "add", "path": "/foo", "value": "1"}], "expected": {"foo":"1"} }, { "comment": "toplevel object, integer", "doc": {}, "patch": [{"op": "add", "path": "/foo", "value": 1}], "expected": {"foo":1} }, { "comment": "Toplevel scalar values OK?", "doc": "foo", "patch": [{"op": "replace", "path": "", "value": "bar"}], "expected": "bar", "disabled": true }, { "comment": "replace object document with array document?", "doc": {}, "patch": [{"op": "add", "path": "", "value": []}], "expected": [] }, { "comment": "replace array document with object document?", "doc": [], "patch": [{"op": "add", "path": "", "value": {}}], "expected": {} }, { "comment": "append to root array document?", "doc": [], "patch": [{"op": "add", "path": "/-", "value": "hi"}], "expected": ["hi"] }, { "comment": "Add, / target", "doc": {}, "patch": [ {"op": "add", "path": "/", "value":1 } ], "expected": {"":1} }, { "comment": "Add, /foo/ deep target (trailing slash)", "doc": {"foo": {}}, "patch": [ {"op": "add", "path": "/foo/", "value":1 } ], "expected": {"foo":{"": 1}} }, { "comment": "Add composite value at top level", "doc": {"foo": 1}, "patch": [{"op": "add", "path": "/bar", "value": [1, 2]}], "expected": {"foo": 1, "bar": [1, 2]} }, { "comment": "Add into composite value", "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, "patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}], "expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} }, { "doc": {"bar": [1, 2]}, "patch": [{"op": "add", "path": "/bar/8", "value": "5"}], "error": "Out of bounds (upper)" }, { "doc": {"bar": [1, 2]}, "patch": [{"op": "add", "path": "/bar/-1", "value": "5"}], "error": "Out of bounds (lower)" }, { "doc": {"foo": 1}, "patch": [{"op": "add", "path": "/bar", "value": true}], "expected": {"foo": 1, "bar": true} }, { "doc": {"foo": 1}, "patch": [{"op": "add", "path": "/bar", "value": false}], "expected": {"foo": 1, "bar": false} }, { "doc": {"foo": 1}, "patch": [{"op": "add", "path": "/bar", "value": null}], "expected": {"foo": 1, "bar": null} }, { "comment": "0 can be an array index or object element name", "doc": {"foo": 1}, "patch": [{"op": "add", "path": "/0", "value": "bar"}], "expected": {"foo": 1, "0": "bar" } }, { "doc": ["foo"], "patch": [{"op": "add", "path": "/1", "value": "bar"}], "expected": ["foo", "bar"] }, { "doc": ["foo", "sil"], "patch": [{"op": "add", "path": "/1", "value": "bar"}], "expected": ["foo", "bar", "sil"] }, { "doc": ["foo", "sil"], "patch": [{"op": "add", "path": "/0", "value": "bar"}], "expected": ["bar", "foo", "sil"] }, { "comment": "push item to array via last index + 1", "doc": ["foo", "sil"], "patch": [{"op":"add", "path": "/2", "value": "bar"}], "expected": ["foo", "sil", "bar"] }, { "comment": "add item to array at index > length should fail", "doc": ["foo", "sil"], "patch": [{"op":"add", "path": "/3", "value": "bar"}], "error": "index is greater than number of items in array" }, { "comment": "test against implementation-specific numeric parsing", "doc": {"1e0": "foo"}, "patch": [{"op": "test", "path": "/1e0", "value": "foo"}], "expected": {"1e0": "foo"} }, { "comment": "test with bad number should fail", "doc": ["foo", "bar"], "patch": [{"op": "test", "path": "/1e0", "value": "bar"}], "error": "test op shouldn't get array element 1" }, { "doc": ["foo", "sil"], "patch": [{"op": "add", "path": "/bar", "value": 42}], "error": "Object operation on array target" }, { "doc": ["foo", "sil"], "patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}], "expected": ["foo", ["bar", "baz"], "sil"], "comment": "value in array add not flattened" }, { "doc": {"foo": 1, "bar": [1, 2, 3, 4]}, "patch": [{"op": "remove", "path": "/bar"}], "expected": {"foo": 1} }, { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, "patch": [{"op": "remove", "path": "/baz/0/qux"}], "expected": {"foo": 1, "baz": [{}]} }, { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, "patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}], "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} }, { "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]}, "patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}], "expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} }, { "doc": ["foo"], "patch": [{"op": "replace", "path": "/0", "value": "bar"}], "expected": ["bar"] }, { "doc": [""], "patch": [{"op": "replace", "path": "/0", "value": 0}], "expected": [0] }, { "doc": [""], "patch": [{"op": "replace", "path": "/0", "value": true}], "expected": [true] }, { "doc": [""], "patch": [{"op": "replace", "path": "/0", "value": false}], "expected": [false] }, { "doc": [""], "patch": [{"op": "replace", "path": "/0", "value": null}], "expected": [null] }, { "doc": ["foo", "sil"], "patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}], "expected": ["foo", ["bar", "baz"]], "comment": "value in array replace not flattened" }, { "comment": "replace whole document", "doc": {"foo": "bar"}, "patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}], "expected": {"baz": "qux"} }, { "comment": "test replace with missing parent key should fail", "doc": {"bar": "baz"}, "patch": [{"op": "replace", "path": "/foo/bar", "value": false}], "error": "replace op should fail with missing parent key" }, { "comment": "spurious patch properties", "doc": {"foo": 1}, "patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}], "expected": {"foo": 1} }, { "doc": {"foo": null}, "patch": [{"op": "test", "path": "/foo", "value": null}], "expected": {"foo": null}, "comment": "null value should be valid obj property" }, { "doc": {"foo": null}, "patch": [{"op": "replace", "path": "/foo", "value": "truthy"}], "expected": {"foo": "truthy"}, "comment": "null value should be valid obj property to be replaced with something truthy" }, { "doc": {"foo": null}, "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], "expected": {"bar": null}, "comment": "null value should be valid obj property to be moved" }, { "doc": {"foo": null}, "patch": [{"op": "copy", "from": "/foo", "path": "/bar"}], "expected": {"foo": null, "bar": null}, "comment": "null value should be valid obj property to be copied" }, { "doc": {"foo": null}, "patch": [{"op": "remove", "path": "/foo"}], "expected": {}, "comment": "null value should be valid obj property to be removed" }, { "doc": {"foo": "bar"}, "patch": [{"op": "replace", "path": "/foo", "value": null}], "expected": {"foo": null}, "comment": "null value should still be valid obj property replace other value" }, { "doc": {"foo": {"foo": 1, "bar": 2}}, "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}], "expected": {"foo": {"foo": 1, "bar": 2}}, "comment": "test should pass despite rearrangement" }, { "doc": {"foo": [{"foo": 1, "bar": 2}]}, "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}], "expected": {"foo": [{"foo": 1, "bar": 2}]}, "comment": "test should pass despite (nested) rearrangement" }, { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, "patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}], "expected": {"foo": {"bar": [1, 2, 5, 4]}}, "comment": "test should pass - no error" }, { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, "patch": [{"op": "test", "path": "/foo", "value": [1, 2]}], "error": "test op should fail" }, { "comment": "Whole document", "doc": { "foo": 1 }, "patch": [{"op": "test", "path": "", "value": {"foo": 1}}], "disabled": true }, { "comment": "Empty-string element", "doc": { "": 1 }, "patch": [{"op": "test", "path": "/", "value": 1}], "expected": { "": 1 } }, { "doc": { "foo": ["bar", "baz"], "": 0, "a/b": 1, "c%d": 2, "e^f": 3, "g|h": 4, "i\\j": 5, "k\"l": 6, " ": 7, "m~n": 8 }, "patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]}, {"op": "test", "path": "/foo/0", "value": "bar"}, {"op": "test", "path": "/", "value": 0}, {"op": "test", "path": "/a~1b", "value": 1}, {"op": "test", "path": "/c%d", "value": 2}, {"op": "test", "path": "/e^f", "value": 3}, {"op": "test", "path": "/g|h", "value": 4}, {"op": "test", "path": "/i\\j", "value": 5}, {"op": "test", "path": "/k\"l", "value": 6}, {"op": "test", "path": "/ ", "value": 7}, {"op": "test", "path": "/m~0n", "value": 8}], "expected": { "": 0, " ": 7, "a/b": 1, "c%d": 2, "e^f": 3, "foo": [ "bar", "baz" ], "g|h": 4, "i\\j": 5, "k\"l": 6, "m~n": 8 } }, { "comment": "Move to same location has no effect", "doc": {"foo": 1}, "patch": [{"op": "move", "from": "/foo", "path": "/foo"}], "expected": {"foo": 1} }, { "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, "patch": [{"op": "move", "from": "/foo", "path": "/bar"}], "expected": {"baz": [{"qux": "hello"}], "bar": 1} }, { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, "patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}], "expected": {"baz": [{}, "hello"], "bar": 1} }, { "doc": {"baz": [{"qux": "hello"}], "bar": 1}, "patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}], "expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} }, { "comment": "replacing the root of the document is possible with add", "doc": {"foo": "bar"}, "patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}], "expected": {"baz":"qux"}}, { "comment": "Adding to \"/-\" adds to the end of the array", "doc": [ 1, 2 ], "patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ], "expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]}, { "comment": "Adding to \"/-\" adds to the end of the array, even n levels down", "doc": [ 1, 2, [ 3, [ 4, 5 ] ] ], "patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ], "expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]}, { "comment": "test remove with bad number should fail", "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, "patch": [{"op": "remove", "path": "/baz/1e0/qux"}], "error": "remove op shouldn't remove from array with bad number" }, { "comment": "test remove on array", "doc": [1, 2, 3, 4], "patch": [{"op": "remove", "path": "/0"}], "expected": [2, 3, 4] }, { "comment": "test repeated removes", "doc": [1, 2, 3, 4], "patch": [{ "op": "remove", "path": "/1" }, { "op": "remove", "path": "/2" }], "expected": [1, 3] }, { "comment": "test remove with bad index should fail", "doc": [1, 2, 3, 4], "patch": [{"op": "remove", "path": "/1e0"}], "error": "remove op shouldn't remove from array with bad number" }, { "comment": "test replace with bad number should fail", "doc": [""], "patch": [{"op": "replace", "path": "/1e0", "value": false}], "error": "replace op shouldn't replace in array with bad number" }, { "comment": "test copy with bad number should fail", "doc": {"baz": [1,2,3], "bar": 1}, "patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}], "error": "copy op shouldn't work with bad number" }, { "comment": "test move with bad number should fail", "doc": {"foo": 1, "baz": [1,2,3,4]}, "patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}], "error": "move op shouldn't work with bad number" }, { "comment": "test add with bad number should fail", "doc": ["foo", "sil"], "patch": [{"op": "add", "path": "/1e0", "value": "bar"}], "error": "add op shouldn't add to array with bad number" }, { "comment": "missing 'path' parameter", "doc": {}, "patch": [ { "op": "add", "value": "bar" } ], "error": "missing 'path' parameter" }, { "comment": "'path' parameter with null value", "doc": {}, "patch": [ { "op": "add", "path": null, "value": "bar" } ], "error": "null is not valid value for 'path'" }, { "comment": "invalid JSON Pointer token", "doc": {}, "patch": [ { "op": "add", "path": "foo", "value": "bar" } ], "error": "JSON Pointer should start with a slash" }, { "comment": "missing 'value' parameter to add", "doc": [ 1 ], "patch": [ { "op": "add", "path": "/-" } ], "error": "missing 'value' parameter" }, { "comment": "missing 'value' parameter to replace", "doc": [ 1 ], "patch": [ { "op": "replace", "path": "/0" } ], "error": "missing 'value' parameter" }, { "comment": "missing 'value' parameter to test", "doc": [ null ], "patch": [ { "op": "test", "path": "/0" } ], "error": "missing 'value' parameter" }, { "comment": "missing value parameter to test - where undef is falsy", "doc": [ false ], "patch": [ { "op": "test", "path": "/0" } ], "error": "missing 'value' parameter" }, { "comment": "missing from parameter to copy", "doc": [ 1 ], "patch": [ { "op": "copy", "path": "/-" } ], "error": "missing 'from' parameter" }, { "comment": "missing from location to copy", "doc": { "foo": 1 }, "patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ], "error": "missing 'from' location" }, { "comment": "missing from parameter to move", "doc": { "foo": 1 }, "patch": [ { "op": "move", "path": "" } ], "error": "missing 'from' parameter" }, { "comment": "missing from location to move", "doc": { "foo": 1 }, "patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ], "error": "missing 'from' location" }, { "comment": "duplicate ops", "doc": { "foo": "bar" }, "patch": [ { "op": "add", "path": "/baz", "value": "qux", "op": "move", "from":"/foo" } ], "error": "patch has two 'op' members", "disabled": true }, { "comment": "unrecognized op should fail", "doc": {"foo": 1}, "patch": [{"op": "spam", "path": "/foo", "value": 1}], "error": "Unrecognized op 'spam'" }, { "comment": "test with bad array number that has leading zeros", "doc": ["foo", "bar"], "patch": [{"op": "test", "path": "/00", "value": "foo"}], "error": "test op should reject the array value, it has leading zeros" }, { "comment": "test with bad array number that has leading zeros", "doc": ["foo", "bar"], "patch": [{"op": "test", "path": "/01", "value": "bar"}], "error": "test op should reject the array value, it has leading zeros" }, { "comment": "Removing nonexistent field", "doc": {"foo" : "bar"}, "patch": [{"op": "remove", "path": "/baz"}], "error": "removing a nonexistent field should fail" }, { "comment": "Removing deep nonexistent path", "doc": {"foo" : "bar"}, "patch": [{"op": "remove", "path": "/missing1/missing2"}], "error": "removing a nonexistent field should fail" }, { "comment": "Removing nonexistent index", "doc": ["foo", "bar"], "patch": [{"op": "remove", "path": "/2"}], "error": "removing a nonexistent index should fail" }, { "comment": "Patch with different capitalisation than doc", "doc": {"foo":"bar"}, "patch": [{"op": "add", "path": "/FOO", "value": "BAR"}], "expected": {"foo": "bar", "FOO": "BAR"} } ] hana-1.3.6/test/json-patch-tests/.editorconfig0000644000175000017500000000026713724225353020331 0ustar pravipravi# EditorConfig is awesome: http://EditorConfig.org root = true [*] end_of_line = lf insert_final_newline = true charset = utf-8 trim_trailing_whitespace = true indent_style = space hana-1.3.6/test/json-patch-tests/.npmignore0000644000175000017500000000003113724225353017640 0ustar pravipravi.editorconfig .gitignore hana-1.3.6/test/json-patch-tests/README.md0000644000175000017500000000440213724225353017126 0ustar pravipraviJSON Patch Tests ================ These are test cases for implementations of [IETF JSON Patch (RFC6902)](http://tools.ietf.org/html/rfc6902). Some implementations can be found at [jsonpatch.com](http://jsonpatch.com). Test Format ----------- Each test file is a JSON document that contains an array of test records. A test record is an object with the following members: - doc: The JSON document to test against - patch: The patch(es) to apply - expected: The expected resulting document, OR - error: A string describing an expected error - comment: A string describing the test - disabled: True if the test should be skipped All fields except 'doc' and 'patch' are optional. Test records consisting only of a comment are also OK. Files ----- - tests.json: the main test file - spec_tests.json: tests from the RFC6902 spec Writing Tests ------------- All tests should have a descriptive comment. Tests should be as simple as possible - just what's required to test a specific piece of behavior. If you want to test interacting behaviors, create tests for each behavior as well as the interaction. If an 'error' member is specified, the error text should describe the error the implementation should raise - *not* what's being tested. Implementation error strings will vary, but the suggested error should be easily matched to the implementation error string. Try to avoid creating error tests that might pass because an incorrect error was reported. Please feel free to contribute! Credits ------- The seed test set was adapted from Byron Ruth's [jsonpatch-js](https://github.com/bruth/jsonpatch-js/blob/master/test.js) and extended by [Mike McCabe](https://github.com/mikemccabe). License ------- Copyright 2014 The Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. hana-1.3.6/test/json-patch-tests/package.json0000644000175000017500000000061113724225353020133 0ustar pravipravi{ "name": "json-patch-test-suite", "version": "1.1.0", "description": "JSON Patch RFC 6902 test suite", "repository": "github:json-patch/json-patch-tests", "homepage": "https://github.com/json-patch/json-patch-tests", "bugs": "https://github.com/json-patch/json-patch-tests/issues", "keywords": [ "JSON", "Patch", "test", "suite" ], "license": "Apache-2.0" } hana-1.3.6/test/json-patch-tests/spec_tests.json0000644000175000017500000000767713724225353020737 0ustar pravipravi[ { "comment": "4.1. add with missing object", "doc": { "q": { "bar": 2 } }, "patch": [ {"op": "add", "path": "/a/b", "value": 1} ], "error": "path /a does not exist -- missing objects are not created recursively" }, { "comment": "A.1. Adding an Object Member", "doc": { "foo": "bar" }, "patch": [ { "op": "add", "path": "/baz", "value": "qux" } ], "expected": { "baz": "qux", "foo": "bar" } }, { "comment": "A.2. Adding an Array Element", "doc": { "foo": [ "bar", "baz" ] }, "patch": [ { "op": "add", "path": "/foo/1", "value": "qux" } ], "expected": { "foo": [ "bar", "qux", "baz" ] } }, { "comment": "A.3. Removing an Object Member", "doc": { "baz": "qux", "foo": "bar" }, "patch": [ { "op": "remove", "path": "/baz" } ], "expected": { "foo": "bar" } }, { "comment": "A.4. Removing an Array Element", "doc": { "foo": [ "bar", "qux", "baz" ] }, "patch": [ { "op": "remove", "path": "/foo/1" } ], "expected": { "foo": [ "bar", "baz" ] } }, { "comment": "A.5. Replacing a Value", "doc": { "baz": "qux", "foo": "bar" }, "patch": [ { "op": "replace", "path": "/baz", "value": "boo" } ], "expected": { "baz": "boo", "foo": "bar" } }, { "comment": "A.6. Moving a Value", "doc": { "foo": { "bar": "baz", "waldo": "fred" }, "qux": { "corge": "grault" } }, "patch": [ { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } ], "expected": { "foo": { "bar": "baz" }, "qux": { "corge": "grault", "thud": "fred" } } }, { "comment": "A.7. Moving an Array Element", "doc": { "foo": [ "all", "grass", "cows", "eat" ] }, "patch": [ { "op": "move", "from": "/foo/1", "path": "/foo/3" } ], "expected": { "foo": [ "all", "cows", "eat", "grass" ] } }, { "comment": "A.8. Testing a Value: Success", "doc": { "baz": "qux", "foo": [ "a", 2, "c" ] }, "patch": [ { "op": "test", "path": "/baz", "value": "qux" }, { "op": "test", "path": "/foo/1", "value": 2 } ], "expected": { "baz": "qux", "foo": [ "a", 2, "c" ] } }, { "comment": "A.9. Testing a Value: Error", "doc": { "baz": "qux" }, "patch": [ { "op": "test", "path": "/baz", "value": "bar" } ], "error": "string not equivalent" }, { "comment": "A.10. Adding a nested Member Object", "doc": { "foo": "bar" }, "patch": [ { "op": "add", "path": "/child", "value": { "grandchild": { } } } ], "expected": { "foo": "bar", "child": { "grandchild": { } } } }, { "comment": "A.11. Ignoring Unrecognized Elements", "doc": { "foo":"bar" }, "patch": [ { "op": "add", "path": "/baz", "value": "qux", "xyz": 123 } ], "expected": { "foo":"bar", "baz":"qux" } }, { "comment": "A.12. Adding to a Non-existent Target", "doc": { "foo": "bar" }, "patch": [ { "op": "add", "path": "/baz/bat", "value": "qux" } ], "error": "add to a non-existent target" }, { "comment": "A.13 Invalid JSON Patch Document", "doc": { "foo": "bar" }, "patch": [ { "op": "add", "path": "/baz", "value": "qux", "op": "remove" } ], "error": "operation has two 'op' members", "disabled": true }, { "comment": "A.14. ~ Escape Ordering", "doc": { "/": 9, "~1": 10 }, "patch": [{"op": "test", "path": "/~01", "value": 10}], "expected": { "/": 9, "~1": 10 } }, { "comment": "A.15. Comparing Strings and Numbers", "doc": { "/": 9, "~1": 10 }, "patch": [{"op": "test", "path": "/~01", "value": "10"}], "error": "number is not equal to string" }, { "comment": "A.16. Adding an Array Value", "doc": { "foo": ["bar"] }, "patch": [{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }], "expected": { "foo": ["bar", ["abc", "def"]] } } ] hana-1.3.6/test/mine.json0000644000175000017500000000274313724225353014272 0ustar pravipravi[ { "comment": "test remove with bad number should fail", "doc": {"foo": 1, "baz": [{"qux": "hello"}]}, "patch": [{"op": "remove", "path": "/baz/1e0/qux"}], "error": "remove op shouldn't remove from array with bad number" }, { "comment": "test remove on array", "doc": [1, 2, 3, 4], "patch": [{"op": "remove", "path": "/0"}], "expected": [2, 3, 4] }, { "comment": "test remove with bad index should fail", "doc": [1, 2, 3, 4], "patch": [{"op": "remove", "path": "/1e0"}], "error": "remove op shouldn't remove from array with bad number" }, { "comment": "test replace with bad number should fail", "doc": [""], "patch": [{"op": "replace", "path": "/1e0", "value": false}], "error": "replace op shouldn't replace in array with bad number" }, { "comment": "test copy with bad number should fail", "doc": {"baz": [1,2,3], "bar": 1}, "patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}], "error": "copy op shouldn't work with bad number" }, { "comment": "test move with bad number should fail", "doc": {"foo": 1, "baz": [1,2,3,4]}, "patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}], "error": "move op shouldn't work with bad number" }, { "comment": "test add with bad number should fail", "doc": ["foo", "sil"], "patch": [{"op": "add", "path": "/1e0", "value": "bar"}], "error": "add op shouldn't add to array with bad number" } ] hana-1.3.6/test/test_hana.rb0000644000175000017500000000576613724225353014752 0ustar pravipravirequire 'helper' class TestHana < Hana::TestCase def test_no_eval patch = Hana::Patch.new [ { 'op' => 'eval', 'value' => '1' } ] assert_raises(Hana::Patch::Exception) do patch.apply('foo' => 'bar') end end def test_mutate_to_a_does_not_impact_original pointer = Hana::Pointer.new '/foo/bar/baz' x = pointer.to_a x << "omg" assert_equal %w{ foo bar baz omg }, x assert_equal %w{ foo bar baz }, pointer.to_a end def test_split_many pointer = Hana::Pointer.new '/foo/bar/baz' assert_equal %w{ foo bar baz }, pointer.to_a end def test_split_with_trailing pointer = Hana::Pointer.new '/foo/' assert_equal ["foo", ""], pointer.to_a end def test_root pointer = Hana::Pointer.new '/' assert_equal [''], pointer.to_a end def test_escape pointer = Hana::Pointer.new '/f^/oo/bar' assert_equal ['f/oo', 'bar'], pointer.to_a pointer = Hana::Pointer.new '/f^^oo/bar' assert_equal ['f^oo', 'bar'], pointer.to_a end def test_eval_hash pointer = Hana::Pointer.new '/foo' assert_equal 'bar', pointer.eval('foo' => 'bar') pointer = Hana::Pointer.new '/foo/bar' assert_equal 'baz', pointer.eval('foo' => { 'bar' => 'baz' }) end def test_eval_array pointer = Hana::Pointer.new '/foo/1' assert_equal 'baz', pointer.eval('foo' => ['bar', 'baz']) pointer = Hana::Pointer.new '/foo/0/bar' assert_equal 'omg', pointer.eval('foo' => [{'bar' => 'omg'}, 'baz']) end def test_eval_number_as_key pointer = Hana::Pointer.new '/foo/1' assert_equal 'baz', pointer.eval('foo' => { '1' => 'baz' }) end def test_eval_many_below_missing pointer = Hana::Pointer.new '/baz/foo/bar' assert_nil pointer.eval('foo' => 'bar') pointer = Hana::Pointer.new '/foo/bar/baz' assert_nil pointer.eval('foo' => nil) end def test_remove_missing_object_key patch = Hana::Patch.new [ { 'op' => 'remove', 'path' => '/missing_key' } ] assert_raises(Hana::Patch::IndexError) do patch.apply('foo' => 'bar') end end def test_remove_deep_missing_path patch = Hana::Patch.new [ { 'op' => 'remove', 'path' => '/missing_key1/missing_key2' } ] assert_raises(Hana::Patch::IndexError) do patch.apply('foo' => 'bar') end end def test_remove_missing_array_index patch = Hana::Patch.new [ { 'op' => 'remove', 'path' => '/1' } ] assert_raises(Hana::Patch::OutOfBoundsException) do patch.apply([0]) end end def test_remove_missing_object_key_in_array patch = Hana::Patch.new [ { 'op' => 'remove', 'path' => '/1/baz' } ] assert_raises(Hana::Patch::IndexError) do patch.apply([ { 'foo' => 'bar' }, { 'foo' => 'bar' } ]) end end def test_replace_missing_key patch = Hana::Patch.new [ { 'op' => 'replace', 'path' => '/missing_key/field', 'value' => 'asdf' } ] assert_raises(Hana::Patch::MissingTargetException) do patch.apply('foo' => 'bar') end end end hana-1.3.6/test/helper.rb0000644000175000017500000000466013724225353014253 0ustar pravipravirequire 'minitest/autorun' require 'hana' require 'json' module Hana class TestCase < Minitest::Test TESTDIR = File.dirname File.expand_path __FILE__ def self.read_test_json_file file Module.new { tests = JSON.load File.read file tests.each_with_index do |test, i| next unless test['doc'] method = "test_#{test['comment'] || i }" loop do if method_defined? method method = "test_#{test['comment'] || i } x" else break end end define_method(method) do skip "disabled" if test['disabled'] doc = test['doc'] patch = test['patch'] patch = Hana::Patch.new patch if test['error'] assert_raises(*ex(test['error']), test['error']) do patch.apply doc end else assert_equal(test['expected'] || doc, patch.apply(doc)) end end end } end def self.skip regexp, message instance_methods.grep(regexp).each do |method| define_method(method) { skip message } end end private def ex msg case msg when /Out of bounds/i then [Hana::Patch::OutOfBoundsException] when /index is greater than/i then [Hana::Patch::OutOfBoundsException] when /Object operation on array/ then [Hana::Patch::ObjectOperationOnArrayException] when /test op shouldn't get array element/ then [Hana::Patch::IndexError, Hana::Patch::ObjectOperationOnArrayException] when /bad number$/ then [Hana::Patch::IndexError, Hana::Patch::ObjectOperationOnArrayException] when /removing a nonexistent (field|index)/ then [Hana::Patch::IndexError, Hana::Patch::OutOfBoundsException] when /test op should reject the array value, it has leading zeros/ then [Hana::Patch::IndexError] when /missing '(from|value)' parameter/ then [KeyError] when /Unrecognized op 'spam'/ then [Hana::Patch::Exception] when /missing 'path'|null is not valid value for 'path'/ then [Hana::Patch::InvalidPath] when /missing|non-existent/ then [Hana::Patch::MissingTargetException] when /JSON Pointer should start with a slash/ then [Hana::Pointer::FormatError] else [Hana::Patch::FailedTestException] end end end end hana-1.3.6/test/test_ietf.rb0000644000175000017500000000077013724225353014760 0ustar pravipravirequire 'helper' module Hana class TestIETF < TestCase filename = File.join TESTDIR, 'json-patch-tests', 'tests.json' include read_test_json_file filename end class TestSpec < TestCase filename = File.join TESTDIR, 'json-patch-tests', 'spec_tests.json' include read_test_json_file filename skip(/A\.13/, 'This test depends on the JSON parser') end class MyTests < TestCase filename = File.join TESTDIR, 'mine.json' include read_test_json_file filename end end hana-1.3.6/hana.gemspec0000644000175000017500000000403313724225353013736 0ustar pravipravi######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: hana 1.3.6 ruby lib Gem::Specification.new do |s| s.name = "hana".freeze s.version = "1.3.6" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "homepage_uri" => "http://github.com/tenderlove/hana" } if s.respond_to? :metadata= s.require_paths = ["lib".freeze] s.authors = ["Aaron Patterson".freeze] s.date = "2020-05-04" s.description = "Implementation of [JSON Patch][1] and [JSON Pointer][2] RFC.".freeze s.email = ["aaron@tenderlovemaking.com".freeze] s.extra_rdoc_files = ["Manifest.txt".freeze, "README.md".freeze] s.files = ["Manifest.txt".freeze, "README.md".freeze, "Rakefile".freeze, "lib/hana.rb".freeze, "test/helper.rb".freeze, "test/json-patch-tests/.editorconfig".freeze, "test/json-patch-tests/.npmignore".freeze, "test/json-patch-tests/README.md".freeze, "test/json-patch-tests/package.json".freeze, "test/json-patch-tests/spec_tests.json".freeze, "test/json-patch-tests/tests.json".freeze, "test/mine.json".freeze, "test/test_hana.rb".freeze, "test/test_ietf.rb".freeze] s.homepage = "http://github.com/tenderlove/hana".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.rubygems_version = "3.1.2".freeze s.summary = "Implementation of [JSON Patch][1] and [JSON Pointer][2] RFC.".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 3.22"]) s.add_development_dependency(%q.freeze, ["~> 5.14"]) s.add_development_dependency(%q.freeze, [">= 4.0", "< 7"]) else s.add_dependency(%q.freeze, ["~> 3.22"]) s.add_dependency(%q.freeze, ["~> 5.14"]) s.add_dependency(%q.freeze, [">= 4.0", "< 7"]) end end hana-1.3.6/Rakefile0000644000175000017500000000066613724225353013137 0ustar pravipravi# -*- ruby -*- require 'rubygems' require 'hoe' Hoe.plugins.delete :rubyforge Hoe.plugin :minitest Hoe.plugin :gemspec # `gem install hoe-gemspec` Hoe.plugin :git # `gem install hoe-git` Hoe.spec 'hana' do developer('Aaron Patterson', 'aaron@tenderlovemaking.com') license 'MIT' self.readme_file = 'README.md' self.extra_rdoc_files = FileList['*.rdoc'] extra_dev_deps << ["minitest", "~> 5.0"] end # vim: syntax=ruby