GithubHelp home page GithubHelp logo

ppx_deriving_yojson's People

Contributors

alexknauth avatar anmonteiro avatar ansoandrieu avatar aphelionz avatar c-cube avatar cemerick avatar choeger avatar dbp avatar emillon avatar gasche avatar gerdstolpmann avatar hcarty avatar hongchangwu avatar jacquev6 avatar kit-ty-kate avatar leonidas-from-xiv avatar nathanreb avatar nightblues avatar pbaudin avatar pitag-ha avatar rgrinberg avatar sim642 avatar smondet avatar stevebleazard avatar thierry-martinez avatar whitequark avatar yawaramin avatar zoggy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ppx_deriving_yojson's Issues

cycle detection

Currently, cyclic values lead to a stack overflow. It would be nice to have some option (maybe just for debugging) to get some information where a cycle happened.

# type t = A of t | B [@@deriving to_yojson]
type t = A of t | B
val to_yojson : t -> Yojson.Safe.json = <fun>
# to_yojson B
- : Yojson.Safe.json = `List [`String "B"]
# let rec x = A x
val x : t = A <cycle>
# to_yojson x
Stack overflow during evaluation (looping recursion?).
Raised by primitive operation at file "//toplevel//", line 1, characters 0-42                                         Called from file "//toplevel//", line 1, characters 0-42

Unbound value `to_json`.

I try with a simple code:

mkdir /tmp/test_jbuilder/
touch /tmp/test_jbuilder/test.opam
touch /tmp/test_jbuilder/test.ml
touch /tmp/test_jbuiler/jbuild

I have these lines in the jbuild file.

(library
 ((name        test)
  (public_name test)
  (modules (test))
  (preprocess (pps (ppx_deriving ppx_deriving_yojson ppx_driver.runner -no-check)))
  (libraries (ppx_deriving ppx_deriving_yojson yojson))))

And these lines in the test.ml file.

type t = {hello: string} [@@deriving yojson]
let t = to_yojson {hello = "test"}

When using jbuilder build @install, I have the following error:

    ocamlopt .ppx/ppx_deriving+ppx_deriving_yojson+ppx_driver.runner/ppx.exe
         ppx test.pp.ml
    ocamldep test.depends.ocamldep-output
      ocamlc test.{cmi,cmo,cmt} (exit 2)
(cd _build/default && /home/danny/.opam/ocaml-4.04.0/bin/ocamlc.opt -w -40 -g -bin-annot -I /home/danny/.opam/ocaml-4.04.0/lib/biniou -I /home/danny/.opam/ocaml-4.04.0/lib/easy-format -I /home/danny/.opam/ocaml-4.04.0/lib/ocaml -I /home/danny/.opam/ocaml-4.04.0/lib/ocaml-migrate-parsetree -I /home/danny/.opam/ocaml-4.04.0/lib/ocaml/compiler-libs -I /home/danny/.opam/ocaml-4.04.0/lib/ppx_derivers -I /home/danny/.opam/ocaml-4.04.0/lib/ppx_deriving -I /home/danny/.opam/ocaml-4.04.0/lib/ppx_deriving_yojson -I /home/danny/.opam/ocaml-4.04.0/lib/ppx_tools -I /home/danny/.opam/ocaml-4.04.0/lib/result -I /home/danny/.opam/ocaml-4.04.0/lib/yojson -no-alias-deps -I . -o test.cmo -c -impl test.pp.ml)
File "test.ml", line 2, characters 8-17:
Error: Unbound value to_yojson

Of course, I tried with t_to_yosjon but it doesn't work.

Optional values do not work anymore

Hi,

I have an API that may or may not include some keys, so I used "option" types to mark the result as optional. I believe this used to work, but the code complains about optional values (I'm using version 2.2):

type f = { exist: int; may: int option; } [@@deriving of_yojson]
f_of_yojson (Yojson.Safe.from_string "{\"exist\": 10}")

Which yields - : [> Error of bytes | Ok of f ] = Error "f.may"</code>. When adding the "may"` key, it parses it correctly.

Expose deriver for use by other derivers?

I'm working on a library, https://github.com/apatil/aplomb, that involves a ppx deriver. The deriver needs to emit to_yojson as well as a few other functions that are specific to my library.

Put another way, in the example in the https://github.com/apatil/aplomb/README.md, I currently have [@@deriving yojson,aplomb]. I'd like to shorten that to [@@deriving aplomb] but still have ppx_deriving_yojson generate to_yojson.

Would it make sense to expose ppx_deriving_yojson's deriver in the library so that derivers like mine can use and augment it, or is there an easier way to do what I want?

@whitequark I'd be happy to submit a patch if it makes sense, I see from other issues that you're crunched for time.

Better error messages

It would be good to have meaningful error messages that explain why a json object cannot be parsed into an OCaml derived type.

Type of `of_yojson` not constrained enough

The fix of #2 added constraints but not enough
(c.f. l. 240 it still puts yojson -> _).

This can become a slight annoyance with functors:

module Of_jsonable (T: sig
    type t
    val to_yojson : t -> Yojson.Safe.json
    val of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of t ]
  end) = struct
  let x = 42
end
module Data = struct
  type t = int list [@@deriving yojson]
end
module Bang = Of_jsonable(Data) 

The functor application fails with:

Error: Signature mismatch:
       ...
       Values do not match:
         val of_yojson :
           Yojson.Safe.json -> [ `Error of bytes | `Ok of int list ]
       is not included in
         val of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of t ]

Encoding of variants with no args

Hello,

By now, variant constructors with no arguments, for example Foo in type t = Foo are encoded as
List [`String "Foo"]`. Would it be possible to encoded these as just String "Foo"` ? (and read them back from the same way, of course).

The reason is that it is quite heavy to have to put them in a list. I encouter the problem when wanting to use generated JSON encoder/decoder functions in Ocf wrappers.

No ty_of_yojson_exn defined?

The README says that three functions are defined, including ty_of_yojson_exn. I am only getting the other two functions:

~$ opam list | grep yojson
ppx_deriving_yojson     3.1         JSON codec generator for OCaml >=4.02
yojson                  1.4.1       Yojson is an optimized parsing and printing library for the JSON format
~$ utop
...
# #require "ppx_deriving_yojson";;
# type foo = {a : int} [@@deriving yojson];;
type foo = { a : int; }
val foo_to_yojson : foo -> Yojson.Safe.json = <fun>
val foo_of_yojson : Yojson.Safe.json -> foo Ppx_deriving_yojson_runtime.error_or = <fun>

Is the README out of date, or is something going wrong?

Handling of Map, Set, ...

Do you plan to handle types generated with Map.Make, Set.Make and so on, for example using something like

module Key = struct type t = int let compare = compare end
module Int_map = Map.Make(Key)[@@deriving yojson]

The attribute on a module could mean "derive for all types in the module". I don't know if it's easy, since the Map.S.t is abstract. But may be you could use the Map functions to list elements to create the json structure and re-create the map when reading the json structure.

It might be quite ad-hoc, but useful :)

Custom encoding of variants

Hi,

I've the following json format to parse:
I can have either:

{"type":"address", "content":string}

or:

{"type":"coord", "content":{"latitude":float, "longitude":float}}

And what I would like to do is something like that:

type geo_coord =
  { latitude : float
  ; longitude : float
  } [@@deriving yojson]

type coord =
  | Adresse [@name "address"] of string
  | GeoCoordinates [@name "coord"] of geo_coord
  [@@deriving yojson]
  [@@deriving_field_name "type"]

Is it already possible to do something like that or otherwise, is it possible to add such a feature ?

3.0 release

According to my test-build, the current head works fine with ppx_deriving 3.0, could you please release this as ppx_deriving_yojson 3.0?

(the reason is that otherwise, users of ppx_deriving_yojson are stuck with an old ppx_deriving package)

[@default None] in yojson vs create

type t = {
  x : int;
  y : (int option [@default None]);
} [@@deriving create, yojson]

gives:

type t = { x : int; y : int option; }
val create : x:int -> ?y:int option -> unit -> t
val to_yojson : t -> Yojson.Safe.json
val of_yojson : Yojson.Safe.json -> [ `Error of string | `Ok of t ]

[@default None] is potentially beneficial for yojson because it allows for a missing y on input and output. Unfortunately it causes create to generate a ?y:int option parameter rather than ?y:int.

Is there a way to work around this?

Error locations incorrect when a deriver is missing

Compiling the following reports an error with no location. It should probably be on the j in y: j. This is using the version 3.1 or the latest master branch of ppx_deriving_yojson and ppx_deriving 4.2.1.

test.ml

(* Just a comment *)

type j

type t = {x: int; y: j} [@@deriving yojson]

jbuild

(jbuild_version 1)

(executable
  ((name test)
   (preprocess (pps (ppx_deriving_yojson)))
   (libraries (ppx_deriving_yojson.runtime))))

Build error with:

$ jbuilder build test.exe
      ocamlc .test.eobjs/test.{cmi,cmo,cmt} (exit 2)
(cd _build/default && /home/hcarty/.opam/4.06.0/bin/ocamlc.opt -w -40 -g -bin-annot -I .test.eobjs -I /home/hcarty/.opam/4.06.0/lib/biniou -I /home/hcarty/.opam/4.06.0/lib/easy-format -I /home/hcarty/.opam/4.06.0/lib/ppx_deriving -I /home/hcarty/.opam/4.06.0/lib/ppx_deriving_yojson/runtime -I /home/hcarty/.opam/4.06.0/lib/result -I /home/hcarty/.opam/4.06.0/lib/yojson -no-alias-deps -o .test.eobjs/test.cmo -c -impl test.pp.ml)
File "_none_", line 1:
Error: Unbound value j_to_yojson
Hint: Did you mean to_yojson?

decoding a float from a json int

utop # type t = {price: float} [@@deriving yojson];;
type t = { price : float; }
val to_yojson : t -> Yojson.Safe.json = <fun>
val of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of t ] = <fun>
utop # Yojson.Safe.from_string "{\"price\":0}";;
- : Yojson.Safe.json = `Assoc [("price", `Int 0)]
utop # of_yojson @@ Yojson.Safe.from_string "{\"price\":0}";;
- : [> `Error of bytes | `Ok of t ] = `Error "t.price"

Problem when deserialising large numbers

When using ppx_deriving with js_of_ocaml I have a problem when deserialising not-too-small integers (with ten digits or more). The following code is a minimal example:

open Printf

type x = {
  a: int;
} [@@deriving yojson]

let json =  {json|{"a":9999999999}|json}

let () =
  eprintf
    "test_integer: %S: Back and forth.\n"
    (Yojson.Safe.(to_string(from_string json)))

let () =
  let x =
    x_of_yojson (Yojson.Safe.from_string json)
  in
  match x with
  | Result.Ok(actualx) -> eprintf "test_integer: %d\n" actualx.a
  | Result.Error(mesg) -> eprintf "test_integer: %s\n" mesg

The first test demonstrates that decoding and recoding json text using Yojson works, and especially that js_of_ocaml has no problem with the not-so-small integer constant.

node test_integer.js
test_integer: "{\"a\":9999999999}": Back and forth.
test_integer: Dynamodb_TestInteger.x.a

Replacing the integer type by int64 let the program run without errors:

test_integer: "{\"a\":9999999999}": Back and forth.
test_integer: 9999999999

Is there any special processing in ppx_deriving that could explain this discrepancy? Or is this more likely a js_of_ocaml bug? (The latter hypothesis seems to be ruled out by the first test.)


System information

opam list ppx_deriving ppx_deriving_yojson  yojson
# Available packages for 4.02.3:
ppx_deriving           4.0  Type-driven code generation for OCaml >=4.02
ppx_deriving_yojson    3.0  JSON codec generator for OCaml >=4.02
yojson               1.3.2  Yojson is an optimized parsing and printing library

Problem with recursive polymorphic variants

Here below we see that the generated function c_of_yojson does not return [ Ok of c | Error of string ]:

utop> type a = [ `B of string ] 
                  [@@deriving of_yojson];;

type a = [ `B of id ]
val a_of_yojson :
  Yojson.Safe.json -> [> `Error of id | `Ok of [> `B of string ] ] = <fun>

utop> type b = [a | `C of b list]
          [@@deriving of_yojson];;

type b = [ `B of id | `C of b list ]
val b_of_yojson :
  Yojson.Safe.json ->
  [ `Error of id | `Ok of [> `B of string | `C of 'a list ] as 'a ] = <fun>

utop> type c = [ a | b | `D of b list]
          [@@deriving of_yojson]
          let c_of_yojson yj : [ `Ok of c | `Error of string ] = c_of_yojson yj;;
(* We try to constrain the type here. *)

Error: This expression has type
         [> `Error of id
          | `Ok of [> `B of string | `C of 'a list | `D of b list ] as 'a ]
       but an expression was expected of type [ `Error of string | `Ok of c ]
       Type 'a is not compatible with type
         c = [ `B of string | `C of b list | `D of b list ] 
       Type c = [ `B of string | `C of b list | `D of b list ]
       is not compatible with type b = [ `B of string | `C of b list ] 
       The second variant type does not allow tag(s) `D

Note that if we “inline” the defintion of c it works again:

utop> type c = [ `B of string | `C of b list | `D of b list ]
          [@@deriving of_yojson]
          let c_of_yojson yj : [ `Ok of c | `Error of string ] = c_of_yojson yj  ;;

type c = [ `B of string | `C of b list | `D of b list ]
val c_of_yojson : Yojson.Safe.json -> [ `Error of string | `Ok of c ] = <fun>

With type b = [a | C of something_else list]`` being not recursive, it also works.

PS: I'd be interested in any other work around that problem, because my real-world use case is pretty big and inlining all the subtyping relationships would be very annoying.

Bad handling of multiply parametrized types

With the following example:

type t1 = int[@@deriving yojson]
type t2 = string[@@deriving yojson]

type ('a, 'b) msg = [ `A of 'a | `B of 'b][@@deriving yojson]

type t = (t1, t2) msg [@@deriving yojson]

The generated msg_of_yojson function is typed as:

val msg_of_yojson : 
  (Yojson.Safe.json -> [ `Error of string | `Ok of 'a ]) ->
  (Yojson.Safe.json -> [ `Error of string | `Ok of 'a ]) ->
  Yojson.Safe.json -> [> `Error of string | `Ok of [> `A of 'a | `B of 'a ] ]

Thus the the generated function t_of_yojson cannot be typed, as the type of msg_of_yojson should rather be

val msg_of_yojson :
  (Yojson.Safe.json -> [ `Error of string | `Ok of 'a ]) ->
  (Yojson.Safe.json -> [ `Error of string | `Ok of 'b ]) ->
  Yojson.Safe.json -> [> `Error of string | `Ok of [> `A of 'a | `B of 'b ] ]

[edited to fix confusion between of_yojson and to_yojson)]

Support for open types

Hello,

Do you plan to support open types ?

type t = .. [@@deriving yojson]

by now gives "yojson cannot be derived for open types".

Maybe this could be achieved by creating a reference to a function when the open type is delcared, then adding handlers to the function for each "+=" declaration ?

Order not kept in list

Serializing then deserializing values encoded with the generated functions does no preserve list order:

type bar = int list [@@deriving Yojson]

let l = [ 1 ; 2 ; 3 ; 4 ]
let l2 = match bar_of_yojson (bar_to_yojson l) with
    `Error msg -> failwith msg
  | `Ok x -> x;;

print_endline (String.concat ", " (List.map string_of_int l));;
print_endline (String.concat ", " (List.map string_of_int l2));;

will give

1, 2, 3, 4
4, 3, 2, 1

support for OCaml >=4.04.0

Installation via opam pin fails for OCaml versions 4.04.0 and 4.04.1:

# Error: This expression has type
# [...]
#        but an expression was expected of type
#          Ast_405.Parsetree.attributes = Ast_405.Parsetree.attribute list
#        Type Parsetree.attribute = string Asttypes.loc * Parsetree.payload
#        is not compatible with type
#          Ast_405.Parsetree.attribute =
#            string Ast_405.Asttypes.loc * Ast_405.Parsetree.payload
#        Type Parsetree.payload is not compatible with type
#          Ast_405.Parsetree.payload

Is this easy to fix?

Deriving with ocaml 4.05

kmicinski-17:symdroid kmicinski$ opam install -y ppx_deriving_yojson
The following dependencies couldn't be met:
  - ppx_deriving_yojson -> ppx_deriving < 3.0
Your request can't be satisfied:
  - ppx_deriving<1.0 is not available because your system doesn't comply with ocaml-version >= "4.02.0" & ocaml-version < "4.03".
  - ppx_deriving<2.0 is not available because your system doesn't comply with ocaml-version = "4.02.1" & ocaml-version < "4.03" & opam-version >= "1.2".
  - ppx_deriving<3.0 is not available because your system doesn't comply with ocaml-version >= "4.02.2" & ocaml-version < "4.03" & opam-version >= "1.2".

This confuses me, because if I'm reading the other issues correctly, it appears that I should be able to install.

Allow string (de)serialization

Supporting string (de)serialization for types that do not support yojson functions may help library authors make use of ppx_deriving_yojson. This could use the existing convention of labeling a type with [@encoding string] to do string serialization instead of yojson serialization for large numbers. For example consider the (pseudo) code below:

module A : sig
  (* This module comes from package a *)
  type t
  val to_string : t -> string
  val of_string : string -> t
end

module B : sig
  (* This module comes from package b *)
  type t [@@deriving yojson]
end

module C : sig
  (* Somebody's trying to write this module in package c, with a and b as dependencies *)
  type t =
    | A of (A.t [@encoding `string])
    | B of B.t
    [@@deriving yojson]
end

The effect here would be that C.to_yojson would encode a B variant normally, but would encode an A variant with the leading "A" tag as usual, while using A.to_string to encode the value that variant contains.

I was looking into implementing this but thought to solicit feedback before proceeding much more. Thoughts?

Is there a way to install with opam and ocaml 4.03.0?

Hi,

Trying to install with opam:

> opam install ppx_deriving_yojson
Your request can't be satisfied:
  - ppx_deriving_yojson is not available because your system doesn't comply with ocaml-version < "4.03.0".
No solution found, exiting

Trying to use the github version:

> opam pin add ppx_deriving_yojson https://github.com/whitequark/ppx_deriving_yojson
ppx_deriving_yojson is now http-pinned to https://github.com/whitequark/ppx_deriving_yojson

[ppx_deriving_yojson] https://github.com/whitequark/ppx_deriving_yojson downloaded

ppx_deriving_yojson needs to be installed.
[ERROR] ppx_deriving_yojson.2.4 is not available because your system doesn't comply with ocaml-version < "4.03.0".

So is there any other way to install ppx_deriving_yojson with opam when you have ocaml 4.03.0?

Thanks.

Warnings

I'm not sure how simple these are to fix, but it would be nice to either fix what is causing the warnings or, if it's possible, silence the warnings with the equivalent of appropriate [@@warnings ...] attributes.

Examples from utop:

utop # #warnings "A";;
utop # type t = { foo : string; bar : string } [@@deriving yojson];;
Characters 0-59:
Warning 39: unused rec flag.
type t = { foo : bytes; bar : bytes; }
val to_yojson : t -> Yojson.Safe.json = <fun>
val of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of t ] = <fun>

utop # type tt = A | B [@@deriving yojson];;
Characters 0-35:
Warning 39: unused rec flag.
Characters 0-35:
Warning 33: unused open Ppx_deriving_yojson_runtime.
type tt = A | B
val tt_to_yojson : tt -> Yojson.Safe.json = <fun>
val tt_of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of tt ] = <fun>

Need to #require "ppx_deriving" before [@@deriving Yojson] works

As stated in the title it appears that #require "ppx_deriving_yojson";; isn't enough from the toplevel.

Using v1.0 from opam with OCaml 4.02.0 and utop 1.15:

utop # #require "ppx_deriving_yojson";;
utop # type t = int [@@deriving Yojson];;
type t = int
utop # #require "ppx_deriving";;
utop # type t = int [@@deriving Yojson];;
type t = int
val to_yojson : 'a -> [> `Int of 'a ] = <fun>
val of_yojson : [> `Int of 'a ] -> [> `Error of bytes | `Ok of 'a ] = <fun>

Can't `make`

Using 4.03.0, cppo 1.4.1, ppx_deriving 4.1

[…]
+ ocamlfind ocamlopt -package unix -package ocamlbuild -linkpkg -package cppo_ocamlbuild myocamlbuild.ml /Users/isaachodes/.opam/4.03.0/lib/ocamlbuild/ocamlbuild.cmx -o myocamlbuild
File "_none_", line 1:
Warning 58: no cmx file was found in path for module Ocamlbuild_cppo, and its interface was not compiled with -opaque

Implicit vs. explicit defaults give different output

type t = {
  outfile         : string option;
  includes        : string list  [@default []];
  kernel_includes : string list;
  (* ... *)
} [@@deriving yojson, create]
let _ = print_endline @@ Yojson.Safe.to_string @@ to_yojson @@ create ()
(* {"outfile":null,"kernel_includes":[]} *)

In this example includes won't be emitted while the other fields will.
Is there a reason for this? Shouldn't they behave the same?

default values and ocaml 4.02.2

in ocaml 4.02.2 I get this

utop # #require "ppx_deriving_yojson";;
utop # type pagination = {
  pages   : int;
  current : int [@default 0];
} [@@deriving yojson];;
type pagination = { pages : int; current : int; }                                                                                                                                                           
 val pagination_to_yojson : pagination -> Yojson.Safe.json = <fun>
 val pagination_of_yojson : Yojson.Safe.json -> [ `Error of bytes | `Ok of pagination ] = <fun>
utop # pagination_of_yojson (Yojson.Safe.from_string "{ pages : 4 }");;
- : [ `Error of bytes | `Ok of pagination ] = `Error "pagination.current" 

while in ocaml 4.02.1 the output used to be

utop # #require "ppx_deriving_yojson";;
utop # type pagination = {
  pages   : int;
  current : int [@default 0];
} [@@deriving yojson];;
type pagination = { pages : int; current : int; }                                                                                                                                                            val pagination_to_yojson : pagination -> Yojson.Safe.json = <fun>
val pagination_of_yojson : Yojson.Safe.json -> [ `Error of bytes | `Ok of pagination ] = <fun>
utop # pagination_of_yojson (Yojson.Safe.from_string "{ pages : 4 }");;
- : [ `Error of bytes | `Ok of pagination ] = `Ok {pages = 4; current = 0}  

all of this is output from utop.

also ocaml 4.02.1 accepts

type t = { a [@name "A"] : int; };;

while ocaml 4.02.2 complains about a syntax error.

Custom de/serializers for datatypes

Given a JSON object like this:

{
    "username": "foo",
    "signupDate": "2016-01-01T23:00:00Z"
}

It would be nice to be able to represent this with a datatype:

type user = {
    username: string;
    signupDate: Core.Time.t [@fromjson core_time_of_yojson] [@tojson core_time_to_yojson];
} [@@deriving yojson]

where core_time_of_yojson is some method that converts Yojson's string representation of the signupDate json field to a Core.Time.t, and core_time_to_yojson is a similar method working the other direction.

of_yojson_exn breaks code that defines of/to_yojson by hand

I'm commenting a bit late on the issue, but adding of_yojson_exn (see #68) breaks all code that defines of_yojson by hand ([@@deriving of_yojson] in the mli, let of_yojson in the ml).

This means that to support this, users will have to copy/paste let of_yojson_exn json = match of_yojson json with Ok x -> x | Error e -> failwith e or similar. It would be nice if ppx_deriving_yojson could handle these cases automatically, but it's unfortunately not possible.

I suggest that we revert this part before the next release and advise users to use a combinator like CCResult.get_exn or RResult.R.get_ok. An alternative is to make this feature opt-in: for example if [@@deriving yojson { exn = true }] is present, generate the of_yojson_exn function in the .ml, and add the corresponding val in the .mli.

Thanks!

Flattening of `option` values

I am unsure how important this is in practice, but the encoding of
option values makes Some (Some (... None)) equal to None.
Could this be an issue [when using types whose definitions are unknown]?

module M : sig
  type t[@@deriving show, yojson]
  val x : t
  val y : t
end = struct
  type t = int option [@@deriving show, yojson]
  let x = None
  let y = Some 1
end

type t = {
  n : string;
  v : M.t option;
}[@@deriving show, yojson]

let x = { n = "x"; v = Some M.x; }

let y = { n = "y"; v = Some M.y; }

let roundtrip v =
  match of_yojson (to_yojson v) with
  | Ok v' ->
    if v = v' then
      Printf.printf "equal\n%!"
    else
      Printf.printf "%S vs %S\n%!" (show v) (show v')
  | Error _ -> assert false

let () =
  roundtrip x;
  roundtrip y

Optional fields

I would like to be able to choose whether I want 'a option fields of OCaml records to be transformed to JSON null values or to be removed from the generated JSON object.

Types are not constrained on to_yojson or of_yojson

Same basic example as #1. I wouldn't expect to see any 'a here.

Using v1.0 from opam with OCaml 4.02.0 and utop 1.15:

utop # #require "yojson";;
utop # #require "ppx_deriving";;
utop # #require "ppx_deriving_yojson";;
utop # type t = int [@@deriving Yojson];;
type t = int
val to_yojson : 'a -> [> `Int of 'a ] = <fun>
val of_yojson : [> `Int of 'a ] -> [> `Error of bytes | `Ok of 'a ] = <fun>

Support [@nobuiltin]

I'd expect the following to work

type unit = { x: int ; y: string } [@@deriving yojson]
type has_unit = { u: unit [@nobuiltin] } [@@deriving yojson]

Does ppx_deriving_yojson support OCaml 4.05?

I met a compile error when I install ppx_deriving_yojson 3.0 in OCaml 4.05.0. It seems that the error depends on the definition of parse tree of OCaml.

$ opam install -y ppx_deriving_yojson
The following actions will be performed:
  - install conf-m4                 1                   [required by ocamlfind]
  - install ocamlfind               1.7.3               [required by ppx_deriving_yojson]
  - install ppx_tools               5.0+4.05.0          [required by ppx_deriving]
  - install jbuilder                1.0+beta12          [required by cppo, cppo_ocamlbuild]
  - install base-bytes              base                [required by cppo]
  - install ppx_derivers            1.0                 [required by ppx_deriving]
  - install ocaml-migrate-parsetree 1.0.4               [required by ppx_deriving]
  - install easy-format             1.3.0               [required by yojson]
  - install cppo                    1.6.0               [required by ppx_deriving_yojson]
  - install biniou                  1.0.6               [required by yojson]
  - install cppo_ocamlbuild         1.6.0               [required by ppx_deriving_yojson]
  - install yojson                  1.3.3               [required by ppx_deriving_yojson]
  - install ppx_deriving            4.2                 [required by ppx_deriving_yojson]
  - install ppx_deriving_yojson     3.0       
===== 14 to install =====

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[biniou] Archive in cache
[cppo] Archive in cache
[cppo_ocamlbuild] Archive in cache
[easy-format] Archive in cache
[jbuilder] Archive in cache
[ocaml-migrate-parsetree] Archive in cache
[ocamlfind] Archive in cache
[ppx_derivers] Archive in cache
[ppx_deriving] Archive in cache
[ppx_deriving_yojson] Archive in cache
[ppx_tools] Archive in cache
[yojson] Archive in cache

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-> installed conf-m4.1
-> installed ocamlfind.1.7.3
-> installed base-bytes.base
-> installed ppx_tools.5.0+4.05.0
-> installed jbuilder.1.0+beta12
-> installed easy-format.1.3.0
-> installed ppx_derivers.1.0
-> installed cppo.1.6.0
-> installed cppo_ocamlbuild.1.6.0
-> installed biniou.1.0.6
-> installed ocaml-migrate-parsetree.1.0.4
-> installed yojson.1.3.3
-> installed ppx_deriving.4.2
[ERROR] The compilation of ppx_deriving_yojson failed at "ocaml pkg/build.ml
        native=true native-dynlink=true".

#=== ERROR while installing ppx_deriving_yojson.3.0 ===========================#
# opam-version 1.2.2
# os           linux
# command      ocaml pkg/build.ml native=true native-dynlink=true
# path         /home/opam/.opam/4.05.0/build/ppx_deriving_yojson.3.0
# compiler     4.05.0
# exit-code    10
# env-file     /home/opam/.opam/4.05.0/build/ppx_deriving_yojson.3.0/ppx_deriving_yojson-597-cbd16a.env
# stdout-file  /home/opam/.opam/4.05.0/build/ppx_deriving_yojson.3.0/ppx_deriving_yojson-597-cbd16a.out
# stderr-file  /home/opam/.opam/4.05.0/build/ppx_deriving_yojson.3.0/ppx_deriving_yojson-597-cbd16a.err
### stdout ###
# [...]
# ocamlfind ocamldep -package result -package ppx_tools.metaquot -package ppx_deriving.api -modules src/ppx_deriving_yojson.ml > src/ppx_deriving_yojson.ml.depends
# ocamlfind ocamlc -c -bin-annot -safe-string -package result -package ppx_tools.metaquot -package ppx_deriving.api -w @5@8@10@11@12@14@23@24@26@29@40 -I src -o src/ppx_deriving_yojson.cmo src/ppx_deriving_yojson.ml
# + ocamlfind ocamlc -c -bin-annot -safe-string -package result -package ppx_tools.metaquot -package ppx_deriving.api -w @5@8@10@11@12@14@23@24@26@29@40 -I src -o src/ppx_deriving_yojson.cmo src/ppx_deriving_yojson.ml
# findlib: [WARNING] Interface topdirs.cmi occurs in several directories: /home/opam/.opam/4.05.0/lib/ocaml, /home/opam/.opam/4.05.0/lib/ocaml/compiler-libs
# File "src/ppx_deriving_yojson.cppo.ml", line 263, characters 24-33:
# Error: This expression has type string list
#        but an expression was expected of type Ast_helper.str list
#        Type string is not compatible with type
#          Ast_helper.str = string Location.loc 
# Command exited with code 2.



=-=- Error report -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
The following actions failed
  - install ppx_deriving_yojson 3.0
The following changes have been performed
  - install base-bytes              base      
  - install biniou                  1.0.6     
  - install conf-m4                 1         
  - install cppo                    1.6.0     
  - install cppo_ocamlbuild         1.6.0     
  - install easy-format             1.3.0     
  - install jbuilder                1.0+beta12
  - install ocaml-migrate-parsetree 1.0.4     
  - install ocamlfind               1.7.3     
  - install ppx_derivers            1.0       
  - install ppx_deriving            4.2       
  - install ppx_tools               5.0+4.05.0
  - install yojson                  1.3.3     

The former state can be restored with:
    opam switch import "~/.opam/4.05.0/backup/state-20170724063417.export"

Type name `t` yields strange constructor function names

When the type is named t, the prefix is omitted:

type t = { has_2fa: bool; } [@@deriving of_yojson];;
type t = { has_2fa: bool; }
val of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of t ] = <fun>

OTOH, with a different name:

type f = { has_2fa: bool; } [@@deriving of_yojson];;
type f = { has_2fa : bool; }
val f_of_yojson : Yojson.Safe.json -> [> `Error of bytes | `Ok of f ] = <fun>

I'm not sure this is a bug, since it clearly targets the Module.t case, but maybe it could be somehow restricted. Or maybe just documented, since this looks useful, but is not mentioned in the readme.

4.03.0 support

The build fails when building under 4.03.0, both from opam and master.

infinite loop in presence of nonrec types

utop # #require "ppx_deriving_yojson";;

utop # type t = A | B [@@deriving yojson];;

utop # module M = struct type nonrec t = t [@@deriving yojson] end;;

utop # M.to_yojson A;;
(* never returns *)
^CInterrupted.

(* Work around by using different type name. *)
utop # module M = struct type u = t [@@deriving yojson] end;;

utop # M.u_to_yojson A;;
- : Yojson.Safe.json = `List [`String "A"]

Add an attribute for dynamic json.

It would be great to have something like a [@DYN] attribute to allow a field of an object not to be parsed but instead be returned as a Yojson.Safe.t value. This is useful when a json object returned from some web app can change the type of a field.

Associative lists as JSON objects

Hi

Is there a way to get an associative list to be converted to a JSON object instead of an array of arrays, similarly to atdgen's <json repr="object">?

Importing json object with uppercase fields.

My use case: I want to be able to define types that match existing JSON objects, whose fields sometimes start with an uppercase letter. Currently it seems impossible to achieve this using ppx_deriving_yojson. I would like to switch from atdgen to this library, but I still need that feature. Is there any plan to implement something like this ?

Cannot compose polymorphic variant types

In t.ml:

type t = [ `A of string ] [@@deriving Yojson]
type u = [ `B of int ] [@@deriving Yojson]
type v = [ t | u ] [@@deriving Yojson]

compiled with:

$ ocamlfind ocamlc -o t.x -package yojson,ppx_deriving t.ml

gives:

Error: This pattern matches values of type [? `A of string ]
       but a pattern was expected which matches values of type
         Yojson.Safe.json
       The second variant type does not allow tag(s) `A

Unable to derive from a type

Hello,

I have the following code:

type call_id = int [@@deriving yojson]
type 'a msg = [
  | `Call of call_id * 'a
  | `Return of call_id * 'a
  ] [@@deriving yojson]

type foo = [`A of foo msg | `B of foo ] [@@deriving yojson]

type server_msg = [ `Foo of server_msg | server_msg msg ]
  [@@deriving yojson]

I get an error:

yojson cannot be derived for [ `Foo of server_msg | server_msg msg]

I don't understand what's wrong with the server_msg definition. Did I miss something ?

Extensible (polymorphic) variants

This code defeats ppx_deriving_yojson:

     type 't a = [ | `A of 't ]
     type 't ext = [ | 't a | `B of 't ]

The problem seems to lie with the ext_of_yojson function.

Here's the error as shown in utop

utop[2]> type 't ext = [ | 't a | `B of 't ][@@deriving yojson];;
Error: This definition has type
         (Yojson.Safe.json -> 't Ppx_deriving_yojson_runtime.error_or) ->
         Yojson.Safe.json -> 't ext Ppx_deriving_yojson_runtime.error_or
       which is less general than
         't0.
           (Yojson.Safe.json -> 't0 Ppx_deriving_yojson_runtime.error_or) ->
           Yojson.Safe.json -> 't0 ext Ppx_deriving_yojson_runtime.error_or

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.