Skip to content

Commit

Permalink
Merge pull request #157 from cuihtlauac/add_path
Browse files Browse the repository at this point in the history
Add `path` function
  • Loading branch information
Leonidas-from-XIV authored Apr 18, 2023
2 parents 9fc32d9 + 39877b4 commit 6cb37fd
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- Add Yojson.Raw.Util module to provide combinators for extracting fields
from Yojson.Raw values. (@tmcgilchrist, #163)

- Add `Util.path` function to recurse into an object through a list of keys.
(@cuihtlauac, @Leonidas-from-XIV, #157)

### Removed

### Changed
Expand Down
11 changes: 11 additions & 0 deletions lib/util.ml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ let member name = function
| `Assoc obj -> assoc name obj
| js -> typerr ("Can't get member '" ^ name ^ "' of non-object type ") js

let rec path l obj =
match l with
| [] -> Some obj
| key :: l -> (
match obj with
| `Assoc assoc -> (
match List.assoc key assoc with
| obj -> path l obj
| exception Not_found -> None)
| _ -> None)

let index i = function
| `List l as js ->
let len = List.length l in
Expand Down
4 changes: 4 additions & 0 deletions lib/util.mli
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ val member : string -> t -> t
object [obj], or [`Null] if [k] is not present in [obj].
@raise Type_error if [obj] is not a JSON object. *)

val path : string list -> t -> t option
(* [path l obj] recurses the JSON object [obj] for each key in the path
[l] until the path is empty or there is no such key in the chain. *)

val index : int -> t -> t
(** [index i arr] returns the value at index [i] in the JSON array [arr].
Negative indices count from the end of the list (so -1 is the last
Expand Down
4 changes: 3 additions & 1 deletion test/fixtures.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ let json_value =
("float", `Float 0.);
("string", `String "string");
("list", `List [ `Int 0; `Int 1; `Int 2 ]);
("assoc", `Assoc [ ("value", `Int 42) ]);
]

let json_string =
"{" ^ {|"null":null,|} ^ {|"bool":true,|} ^ {|"int":0,|}
^ {|"intlit":10000000000000000000,|} ^ {|"float":0.0,|}
^ {|"string":"string",|} ^ {|"list":[0,1,2]|} ^ "}"
^ {|"string":"string",|} ^ {|"list":[0,1,2],|} ^ {|"assoc":{"value":42}|}
^ "}"

let unquoted_json = {|{foo: null}|}
let unquoted_value = `Assoc [ ("foo", `Null) ]
Expand Down
1 change: 1 addition & 0 deletions test/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ let () =
("equality", Test_monomorphic.equality);
("read", Test_read.single_json);
("write", Test_write.single_json);
("util", Test_util.tests);
]
22 changes: 22 additions & 0 deletions test/test_util.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
let path_empty () =
Alcotest.(check (option Testable.yojson))
__LOC__ (Some Fixtures.json_value)
(Yojson.Safe.Util.path [] Fixtures.json_value)

let path_missing () =
Alcotest.(check (option Testable.yojson))
__LOC__ None
(Yojson.Safe.Util.path [ "does not exist" ] Fixtures.json_value)

let path_traverse () =
Alcotest.(check (option Testable.yojson))
__LOC__
(Some (`Int 42))
(Yojson.Safe.Util.path [ "assoc"; "value" ] Fixtures.json_value)

let tests =
[
("empty path", `Quick, path_empty);
("non-existing path", `Quick, path_missing);
("traversal", `Quick, path_traverse);
]
1 change: 1 addition & 0 deletions test/test_util.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
val tests : unit Alcotest.test_case list

0 comments on commit 6cb37fd

Please sign in to comment.