Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify Json and ppx runtime modules #45

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Based on [@glennsl/bs-json](https://github.com/glennsl/bs-json).
The Decode module in particular provides a basic set of decoder functions to be
composed into more complex decoders. A decoder is a function that takes a
`Js.Json.t` and either returns a value of the desired type if successful or
raises a `DecodeError` exception if not. Other functions accept a decoder and
raises an `Of_json_error` exception if not. Other functions accept a decoder and
produce another decoder. Like `array`, which when given a decoder for type `t`
will return a decoder that tries to produce a value of type `t array`. So to
decode an `int array` you combine `Json.Decode.int` with `Json.Decode.array`
Expand Down
36 changes: 13 additions & 23 deletions examples/complex.ml
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
type line = {
start: point;
end_: point;
thickness: int option
}
and point = {
x: int;
y: int
}
[@@@alert "-deprecated"]
type line = { start : point; end_ : point; thickness : int option }
and point = { x : int; y : int }

module Decode = struct
let point json =
Json.Decode.{
x = json |> field "x" int;
y = json |> field "y" int
}
Json.Decode.{ x = json |> field "x" int; y = json |> field "y" int }

let line json =
Json.Decode.{
start = json |> field "start" point;
end_ = json |> field "end" point;
thickness = json |> optional (field "thickness" int)
}
Json.Decode.
{
start = json |> field "start" point;
end_ = json |> field "end" point;
thickness = json |> optional (field "thickness" int);
}
end

let data = {| {
let data =
{| {
"start": { "x": 1, "y": -4 },
"end": { "x": 5, "y": 8 }
} |}

let _ =
data |> Json.parseOrRaise
|> Decode.line
|> Js.log
let _ = data |> Json.parseOrRaise |> Decode.line |> Js.log
8 changes: 6 additions & 2 deletions examples/decode.ml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
[@@@alert "-deprecated"]

(* Decoding a fixed JSON data structure using Json.Decode *)
let mapJsonObjectString f decoder (encoder : int -> Js.Json.t) str =
let json = Json.parseOrRaise str in
Json.Decode.(dict decoder json)
|> Js.Dict.map ~f:(fun [@u] v -> f v)
|> Json.Encode.dict encoder |> Json.stringify
|> Json.Encode.dict encoder
|> Json.stringify

let sum = Array.fold_left ( + ) 0

Expand All @@ -25,4 +28,5 @@ let _ =
let json = {|{ "y": 42 } |} |> Json.parseOrRaise in
match Json.Decode.(field "x" int json) with
| x -> Js.log x
| exception Json.Decode.DecodeError err -> Js.log ("Error:" ^ Json.Decode.error_to_string err)
| exception Json.Of_json_error err ->
Js.log ("Error:" ^ Json.of_json_error_to_string err)
3 changes: 2 additions & 1 deletion examples/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
(target examples)
(alias examples)
(libraries melange-json)
(preprocess (pps melange.ppx)))
(preprocess
(pps melange.ppx)))
39 changes: 17 additions & 22 deletions examples/dynamicDict_Ocaml.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[@@@alert "-deprecated"]

(*
Handling an object with dynamic keys for sub-objects.
example:
Expand All @@ -13,47 +15,40 @@
Could be dynamic JS keys generated by user or generally at run time.
*)

type obj = {
static: string;
dynamics: int Js.Dict.t;
}
type obj = { static : string; dynamics : int Js.Dict.t }

module Decode = struct
let obj json =
Json.Decode.{
static = json |> field "static" string;
dynamics = json |> field "dynamics" (dict int)
}
Json.Decode.
{
static = json |> field "static" string;
dynamics = json |> field "dynamics" (dict int);
}
end

module Encode = struct
let obj c =
Json.Encode.(
object_ [
"static", c.static |> string;
"dynamics", c.dynamics |> dict int
]
)
object_
[
"static", c.static |> string; "dynamics", c.dynamics |> dict int;
])
end

let data = {| {
let data =
{| {
"static": "hi",
"dynamics": { "hello": 5, "random": 8 }
} |}

let decodedData =
data |> Json.parseOrRaise
|> Decode.obj
let decodedData = data |> Json.parseOrRaise |> Decode.obj

(*
Will log [ 'hi', { hello: 5, random: 8 } ]
*)
let _ =
decodedData |> Js.log
let _ = decodedData |> Js.log

(*
Will log { static: 'hi', dynamics: { hello: 5, random: 8 } }
*)
let encodedDataBack =
decodedData |> Encode.obj
|> Js.log
let encodedDataBack = decodedData |> Encode.obj |> Js.log
51 changes: 24 additions & 27 deletions examples/dynamicDict_Reason.re
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
[@alert "-deprecated"];

/*
Handling an object with dynamic keys for sub-objects.
example:
{
static: "hello",
dynamics: {
"undetermined1": 2
"undetermined2": 6
}
}

Where the "undetermined" keys, are unknown at compile time.
Could be dynamic JS keys generated by user or generally at run time.
*/
Handling an object with dynamic keys for sub-objects.
example:
{
static: "hello",
dynamics: {
"undetermined1": 2
"undetermined2": 6
}
}

Where the "undetermined" keys, are unknown at compile time.
Could be dynamic JS keys generated by user or generally at run time.
*/

type obj = {
static: string,
dynamics: Js.Dict.t(int)
dynamics: Js.Dict.t(int),
};

module Decode = {
Expand All @@ -27,7 +29,7 @@ module Decode = {
};

module Encode = {
let obj = (c) => {
let obj = c => {
Json.Encode.(
object_([
("static", string(c.static)),
Expand All @@ -42,19 +44,14 @@ let data = {| {
"dynamics": { "hello": 5, "random": 8 }
} |};

let decodedData =
data |> Json.parseOrRaise
|> Decode.obj;
let decodedData = data |> Json.parseOrRaise |> Decode.obj;

/*
Will log [ 'hi', { hello: 5, random: 8 } ]
*/
let _ =
decodedData |> Js.log;
Will log [ 'hi', { hello: 5, random: 8 } ]
*/
let _ = decodedData |> Js.log;

/*
Will log { static: 'hi', dynamics: { hello: 5, random: 8 } }
*/
let encodedDataBack =
decodedData |> Encode.obj
|> Js.log;
Will log { static: 'hi', dynamics: { hello: 5, random: 8 } }
*/
let encodedDataBack = decodedData |> Encode.obj |> Js.log;
23 changes: 13 additions & 10 deletions examples/encode.ml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[@@@alert "-deprecated"]
(* Encoding a JSON data structure using Json.Encode *)

(* prints ["foo", "bar"] *)
let _ =
[| "foo"; "bar" |] |> Json.Encode.stringArray |> Json.stringify |> Js.log
[| "foo"; "bar" |]
|> Json.Encode.stringArray
|> Json.stringify
|> Js.log

(* prints ["foo", "bar"] *)
let _ =
Expand All @@ -13,7 +17,8 @@ let _ =
|> Js.log

(* prints { x: 42, foo: 'bar' } *)
let _ = Json.Encode.(object_ [ ("x", int 42); ("foo", string "bar") ] |> Js.log)
let _ =
Json.Encode.(object_ [ "x", int 42; "foo", string "bar" ] |> Js.log)

(* Advanced example: encode a record *)
type line = { start : point; end_ : point; thickness : int option }
Expand All @@ -22,15 +27,16 @@ and point = { x : float; y : float }
module Encode = struct
let point r =
let open! Json.Encode in
object_ [ ("x", float r.x); ("y", float r.y) ]
object_ [ "x", float r.x; "y", float r.y ]

let line r =
Json.Encode.(
object_
[
("start", point r.start);
("end", point r.end_);
("thickness", match r.thickness with Some x -> int x | None -> null);
"start", point r.start;
"end", point r.end_;
( "thickness",
match r.thickness with Some x -> int x | None -> null );
])
end

Expand All @@ -41,7 +47,4 @@ let data =
thickness = Some 2;
}

let _ =
data
|> Encode.line
|> Js.log
let _ = data |> Encode.line |> Js.log
4 changes: 3 additions & 1 deletion examples/parse.ml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
[@@@alert "-deprecated"]

(* Parsing a JSON string using Json.parseOrRaise *)

let arrayOfInts str =
let json = Json.parseOrRaise str in
Json.Decode.(array int json)

(* prints `[3, 2, 1]` *)
let _ = Js.log (arrayOfInts "[1, 2, 3]" |> Js.Array.reverseInPlace)
let _ = Js.log (arrayOfInts "[1, 2, 3]" |> Js.Array.reverseInPlace)
63 changes: 31 additions & 32 deletions examples/tree.ml
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
[@@@alert "-deprecated"]
(* Decode a JSON tree structure *)
type 'a tree =
| Node of 'a * 'a tree list
| Leaf of 'a
type 'a tree = Node of 'a * 'a tree list | Leaf of 'a

module Decode = struct
open Json.Decode

let rec tree decoder =
field "type" string |> andThen (
function | "node" -> node decoder
| "leaf" -> leaf decoder
| _ -> failwith "unknown node type"
)
field "type" string
|> andThen (function
| "node" -> node decoder
| "leaf" -> leaf decoder
| _ -> failwith "unknown node type")

and node decoder json =
Node (
(json |> field "value" decoder),
(json |> field "children" (array (tree decoder) |> map Array.to_list))
)
Node
( json |> field "value" decoder,
json
|> field "children" (array (tree decoder) |> map Array.to_list) )

and leaf decoder json =
Leaf (json |> field "value" decoder)
and leaf decoder json = Leaf (json |> field "value" decoder)
end

let rec indent =
function | n when n <= 0 -> ()
| n -> print_string " "; indent (n - 1)
let rec indent = function
| n when n <= 0 -> ()
| n ->
print_string " ";
indent (n - 1)

let print =
let rec aux level =
function | Node (value, children) ->
indent level;
Js.log value;
children |> List.iter (fun child -> aux (level + 1) child)
| Leaf value ->
indent level;
Js.log value
in
aux 0

let json = {| {
let rec aux level = function
| Node (value, children) ->
indent level;
Js.log value;
children |> List.iter (fun child -> aux (level + 1) child)
| Leaf value ->
indent level;
Js.log value
in
aux 0

let json =
{| {
"type": "node",
"value": 9,
"children": [{
Expand All @@ -59,6 +60,4 @@ let json = {| {
} |}

let myTree =
json |> Json.parseOrRaise
|> Decode.tree Json.Decode.int
|> print
json |> Json.parseOrRaise |> Decode.tree Json.Decode.int |> print
Loading
Loading