Skip to content

Commit 9c4a405

Browse files
committed
tidied up README.md
renamed has! to has? added JSONPointer.Utils to the doctest party changed add return value so that it brings back the list that was changed
1 parent 5ea4509 commit 9c4a405

5 files changed

Lines changed: 115 additions & 169 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## [Unreleased]
66

7-
## Added
7+
### Added
88
- add/add! - adds values indicated by pointers
99
- options can be passed to operations. only option so far is :strict which affects set/add behaviour
10+
- test - checks whether the given pointer has the given value
1011

11-
## Changed
12-
- has/3 changed to test/3
12+
### Changed
13+
- has changed to has? as it returns a single value
1314
- stricter parsing of integer indexes
1415
- increased terseness of error messages
1516
- remove now actually reduces the list size, rather than replace with nil
1617

18+
### Fixed
19+
- corrected parsing of /~01
20+
21+
1722
## v2.5.0
1823
### Added
1924
- support for special array rules - /01 is not evaluated to an integer

README.md

Lines changed: 22 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -12,147 +12,56 @@ An implementation of [JSON Pointer (RFC 6901)](http://tools.ietf.org/html/draft-
1212
Add a dependency to your project `mix.exs`:
1313

1414
```Elixir
15-
1615
def deps do
1716
[{:odgn_json_pointer, "~> 2.5"}]
1817
end
19-
2018
```
2119

22-
Then update your dependencies:
23-
24-
```sh-session
25-
$ mix deps.get
26-
```
27-
28-
29-
## API
30-
31-
### JSONPointer.get(object, pointer)
32-
33-
Retrieves the value indicated by the pointer from the object
20+
## Basic Usage
3421

3522
```Elixir
36-
JSONPointer.get( %{ "fridge" => %{ "door" => "milk" } }, "/fridge/door" )
37-
# => {:ok, "milk"}
38-
```
23+
iex> JSONPointer.get( %{ "fridge" => %{ "door" => "milk" } }, "/fridge/door" )
24+
{:ok, "milk"}
3925

40-
### JSONPointer.get!(object,pointer)
4126

42-
Retrieves the value indicated by the pointer from the object, and raises an error if not found
27+
iex> JSONPointer.set( %{}, "/example/msg", "hello")
28+
{:ok, %{ "example" => %{ "msg" => "hello" }}, nil }
4329

44-
```Elixir
45-
JSONPointer.get!( %{}, "/fridge/milk" )
46-
** (ArgumentError) json pointer key not found: fridge
47-
```
4830

49-
### JSONPointer.set(object, pointer, value)
31+
iex> JSONPointer.add( %{ "fridge" => [ "milk", "cheese" ]}, "/fridge/1", "salad")
32+
{:ok, %{ "fridge" => [ "milk", "salad", "cheese" ]}, [ "milk", "cheese" ] }
5033

51-
Sets the value indicated by the pointer in the object
5234

53-
```Elixir
54-
JSONPointer.set( %{}, "/example/msg", "hello")
55-
# => {:ok, %{ "example" => %{ "msg" => "hello" }}, nil }
56-
```
35+
iex> JSONPointer.has?( %{ "milk" => true, "butter" => false}, "/butter" )
36+
true
5737

58-
### JSONPointer.set!(object, pointer, value)
5938

60-
Sets the value indicated by the pointer in the object, raises an exception on error
39+
iex> JSONPointer.test( %{ "milk" => "skimmed", "butter" => false}, "/milk", "skimmed" )
40+
{:ok, %{ "milk" => "skimmed", "butter" => false} }
6141

62-
```Elixir
63-
JSONPointer.set!( %{}, "/example/msg", "hello")
64-
# => %{ "example" => %{ "msg" => "hello" }}
65-
```
6642

67-
### JSONPointer.dehydrate(object)
43+
iex> JSONPointer.remove( %{"fridge" => %{ "milk" => true, "butter" => true}}, "/fridge/butter" )
44+
{:ok, %{"fridge" => %{"milk"=>true}}, true }
6845

69-
Returns an array of JSON pointer paths mapped to their values
7046

71-
```Elixir
72-
JSONPointer.dehydrate( %{"a"=>%{"b"=>["c","d"]}} )
73-
# => {:ok, [{"/a/b/0", "c"}, {"/a/b/1", "d"}] }
74-
```
47+
iex> JSONPointer.dehydrate( %{"a"=>%{"b"=>["c","d"]}} )
48+
{:ok, [{"/a/b/0", "c"}, {"/a/b/1", "d"}] }
7549

76-
### JSONPointer.dehydrate!(object)
7750

78-
Returns an array of JSON pointer paths mapped to their values, raises an exception on error
51+
iex> iex> JSONPointer.hydrate( [ {"/a/1/b", "single"} ] )
52+
{:ok, %{"a" => %{"1" => %{"b" => "single"}}}}
7953

80-
```Elixir
81-
JSONPointer.dehydrate!( %{"a"=>%{"b"=>["c","d"]}} )
82-
# => [{"/a/b/0", "c"}, {"/a/b/1", "d"}]
83-
```
8454

85-
### JSONPointer.hydrate(container, paths)
55+
iex> JSONPointer.merge( %{"a"=>1}, %{"b"=>2} )
56+
{:ok, %{"a"=>1,"b"=>2} }
8657

87-
Applies the given list of paths to the given container
8858

89-
```Elixir
90-
iex> JSONPointer.hydrate( [ {"/a/1/b", "single"} ] )
91-
# => {:ok, %{"a" => %{"1" => %{"b" => "single"}}}}
92-
```
59+
iex> JSONPointer.transform( %{ "a"=>4, "b"=>%{ "c" => true }}, [ {"/b/c", "/valid"}, {"/a","/count", fn val -> val*2 end} ] )
60+
{:ok, %{"count" => 8, "valid" => true}}
9361

94-
### JSONPointer.hydrate!(container, paths)
95-
96-
Applies the given list of paths to the given container, raises an exception on error
97-
98-
```Elixir
99-
iex> JSONPointer.hydrate!( %{}, [ {"/a/b/1", "find"} ] )
100-
# => {:ok, %{"a"=>%{"b"=>[nil,"find"]} } }
10162
```
10263

103-
### JSONPointer.merge(src,dst)
104-
105-
Merges the dst container into src
106-
107-
```Elixir
108-
JSONPointer.merge( %{"a"=>1}, %{"b"=>2} )
109-
# => {:ok, %{"a"=>1,"b"=>2} }
110-
```
111-
112-
### JSONPointer.merge!(src,dst)
113-
114-
Merges the dst container into src, raises an exception on error
115-
116-
```Elixir
117-
JSONPointer.merge!( %{"a"=>1}, %{"b"=>2} )
118-
# => %{"a"=>1,"b"=>2}
119-
```
120-
121-
### JSONPointer.has(object, pointer)
122-
123-
Returns true if the given value exists in the object indicated by the pointer
124-
125-
```Elixir
126-
JSONPointer.has( %{ "milk" => true, "butter" => false}, "/butter" )
127-
# => true
128-
```
129-
130-
### JSONPointer.remove(object, pointer)
131-
132-
Removes the value from the object indicated by the pointer
133-
134-
```Elixir
135-
JSONPointer.remove( %{"fridge" => %{ "milk" => true, "butter" => true}}, "/fridge/butter" )
136-
# => {:ok, %{"fridge" => %{"milk"=>true}}, true }
137-
```
138-
139-
### JSONPointer.transform(src,mapping)
140-
141-
Applies a mapping of source paths to destination paths in the result
142-
143-
```Elixir
144-
JSONPointer.transform( %{ "a"=>4, "b"=>%{ "c" => true }}, [ {"/b/c", "/valid"}, {"/a","/count", fn val -> val*2 end} ] )
145-
# => {:ok, %{"count" => 8, "valid" => true}}
146-
```
147-
148-
### JSONPointer.transform!(src,mapping)
149-
150-
Applies a mapping of source paths to destination paths in the result, raises an error on exception
151-
152-
```Elixir
153-
JSONPointer.transform!( %{ "a"=>5, "b"=>%{ "is_valid" => true }}, [ {"/b/is_valid", "/valid"}, {"/a","/count", fn val -> val*2 end} ] )
154-
# => %{"count" => 10, "valid" => true}
155-
```
64+
Full documentation can be found at https://hexdocs.pm/odgn_json_pointer.
15665

15766

15867

lib/json_pointer.ex

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ defmodule JSONPointer do
111111
Returns true if the given JSON Pointer resolves to a value
112112
113113
## Examples
114-
iex> JSONPointer.has!( %{ "milk" => true, "butter" => false}, "/butter" )
114+
iex> JSONPointer.has?( %{ "milk" => true, "butter" => false}, "/butter" )
115115
true
116116
117-
iex> JSONPointer.has!( %{ "milk" => true, "butter" => false}, "/cornflakes" )
117+
iex> JSONPointer.has?( %{ "milk" => true, "butter" => false}, "/cornflakes" )
118118
false
119119
"""
120-
@spec has!(container, pointer, options) :: boolean
121-
def has!(obj, pointer, options \\ @default_options) do
120+
@spec has?(container, pointer, options) :: boolean
121+
def has?(obj, pointer, options \\ @default_options) do
122122
case walk_container(:has, obj, pointer, nil, options) do
123123
{:ok, _obj, _existing} -> true
124124
{:error, _, _} -> false
@@ -128,21 +128,15 @@ defmodule JSONPointer do
128128
@doc """
129129
Tests whether a JSON Pointer equals the given value
130130
131+
## Examples
132+
iex> JSONPointer.test( %{ "milk" => "skimmed", "butter" => false}, "/milk", "skimmed" )
133+
{:ok, %{ "milk" => "skimmed", "butter" => false} }
134+
131135
"""
132136
@spec test(container, pointer, t, options) :: {:ok, t} | error_message
133137
def test(obj, pointer, value, options \\ @default_options) do
134-
# with {:ok, result, existing} <- walk_container(:has, obj, pointer, nil, options)
135-
# is_equal <- are_equal?
136-
# do
137-
138-
# else
139-
# {:error, msg, _ } -> {:error, msg}
140-
# end
141-
142138
case walk_container(:get, obj, pointer, nil, options) do
143139
{:ok, result, _} ->
144-
# IO.puts("are_equal? #{pointer} => '#{value}' '#{result}'")
145-
146140
case are_equal?(value, result) do
147141
{:ok, _} -> {:ok, obj}
148142
{:error, msg} -> {:error, msg}
@@ -153,27 +147,22 @@ defmodule JSONPointer do
153147
end
154148
end
155149

156-
# defp are_equal?(val1, val2) when is_binary(val1) and is_binary(val2),
157-
# do:
158-
# if(String.equivalent?(val1, val2), do: {:ok, true}, else: {:error, "string not equivalent"})
159-
160-
defp are_equal?(val1, val2) when is_binary(val1) and is_number(val2),
161-
do: {:error, "number is not equal to string"}
150+
@doc """
151+
Tests whether a JSON Pointer equals the given value, raises an error if they don't
162152
163-
defp are_equal?(val1, val2) when is_number(val1) and is_binary(val2),
164-
do: {:error, "string is not equal to number"}
153+
## Examples
154+
iex> JSONPointer.test!( %{ "milk" => "skimmed", "butter" => false}, "/butter", "unsalted" )
155+
** (ArgumentError) not equal
165156
166-
defp are_equal?(val1, val2) do
167-
if val1 == val2 do
168-
{:ok, true}
169-
else
170-
are_not_equal_error(val1,val2)
157+
"""
158+
@spec test!(container, pointer, t, options) :: t | no_return
159+
def test!(obj, pointer, value, options \\ @default_options) do
160+
case test(obj, pointer, value, options) do
161+
{:ok, result} -> result
162+
{:error, msg} -> raise ArgumentError, message: msg
171163
end
172164
end
173165

174-
defp are_not_equal_error(val1,val2) when is_binary(val1) and is_binary(val2), do: {:error, "string not equivalent"}
175-
defp are_not_equal_error(_val1,_val2), do: {:error, "not equal"}
176-
177166
@doc """
178167
Removes an attribute of object referenced by pointer
179168
@@ -238,6 +227,9 @@ defmodule JSONPointer do
238227
Follows the JSON patch behaviour specified in rfc6902
239228
240229
## Examples
230+
iex> JSONPointer.add( %{ "fridge" => [ "milk", "cheese" ] }, "/fridge/1", "salad")
231+
{:ok, %{ "fridge" => [ "milk", "salad", "cheese" ]}, [ "milk", "cheese" ] }
232+
241233
iex> JSONPointer.add( %{ "a" => %{"b" => %{}}}, "/a/b/c", ["foo", "bar"] )
242234
{:ok, %{"a" => %{"b" => %{"c" => ["foo", "bar"]}}}, nil}
243235
"""
@@ -624,7 +616,8 @@ defmodule JSONPointer do
624616
if is_strict && (index < 0 || index > Enum.count(list)) do
625617
{:error, "index out of bounds: #{index}", list}
626618
else
627-
{:ok, insert_into(list, index, value), Enum.at(list, index)}
619+
# Enum.at(list, index)}
620+
{:ok, insert_into(list, index, value), list}
628621
end
629622
end
630623
end
@@ -863,7 +856,6 @@ defmodule JSONPointer do
863856
if (operation == :get or operation == :has) and index >= Enum.count(list) do
864857
{:error, "index out of bounds: #{index}", list}
865858
else
866-
867859
{res, sub, rem} =
868860
walk_container(
869861
operation,
@@ -876,7 +868,10 @@ defmodule JSONPointer do
876868
)
877869

878870
# a sublety of adding over setting
879-
if operation == :add, do: {res, apply_into( list, index, sub ), list}, else: {res, sub, rem}
871+
if operation == :add,
872+
do: {res, apply_into(list, index, sub), list},
873+
else: {res, sub, rem}
874+
880875
# {res, [sub], list}
881876
end
882877
end

0 commit comments

Comments
 (0)