Library
Module
Module type
Parameter
Class
Class type
This ppx is based on ppx_yojson and ppx_deriving_yojson because of the many similarities between JSON and yaml.
So similar that OCaml's Yaml
library shares a common type with the Ezjsonm library. See ppx_deriving_ezjsonm
for more details.
For converting OCaml values to Yaml values ppx_deriving_yaml
will do the conventional dropping of the type name if it is t
. Otherwise the type name is the prefix to the to_yaml
function.
to_yaml
produces a Yaml.value
.
of_yaml
produces OCaml types wrapped in a Stdlib.result
.
# #require "ppx_deriving_yaml";;
Here is a small example.
type person = { name : string; age : int } [@@deriving yaml]
type users = person list [@@deriving yaml]
This will produce four functions, a _to_yaml
and _of_yaml
for both a person and the users. For example:
# person_to_yaml;;
- : person ->
[> `O of (string * [> `Float of float | `String of string ]) list ]
= <fun>
# users_of_yaml;;
- : [> `A of
[> `O of (string * [> `Float of float | `String of string ]) list ]
list ] ->
(person list, [> `Msg of string ]) result
= <fun>
If your type constructors have arguments, then the functions will be higher-order and you will need to supply a function to convert values for each constructor argument. For example:
type 'a note = { txt : 'a } [@@deriving yaml]
produces the following function.
# note_to_yaml;;
- : ('a -> Yaml.value) -> 'a note -> [> `O of (string * Yaml.value) list ] =
<fun>
Finally, if you only need the encoder (to_yaml
) or the decoder (of_yaml
) then there are single versions of the deriver for those.
# type x = { age : int }[@@deriving to_yaml];;
type x = { age : int; }
val x_to_yaml : x -> [> `O of (string * [> `Float of float ]) list ] = <fun>
Record field names cannot begin with a capital letter and variant constructors must start with one. This limits what the generated Yaml can look like. To override the Yaml names you can use the [@key <string>]
and [@name
<string>]
attributes for records and variants respectively.
# type t = {
camel_name : string [@key "camel-name"]
}[@@deriving to_yaml];;
type t = { camel_name : string; }
val to_yaml : t -> [> `O of (string * [> `String of string ]) list ] = <fun>
# Yaml.to_string_exn (to_yaml { camel_name = "Alice" });;
- : string = "camel-name: Alice\n"
You can also specify default values for fields.
type t = {
name : string;
age : int [@default 42]
}[@@deriving yaml]
These will be used in the absence of any fields when decoding Yaml values into OCaml ones.
# Yaml.of_string_exn "name: Alice" |> of_yaml;;
- : (t, [> `Msg of string ]) result = Ok {name = "Alice"; age = 42}
Sometimes you might want to specify your own encoding and decoding logic on field by field basis. To do so, you can use the of_yaml
and to_yaml
attributes.
type t = {
name : string [@to_yaml fun i -> `String ("custom-" ^ i)]
}[@@deriving yaml]
The to_yaml
function will use the custom encoder now instead.
# Yaml.to_string_exn (to_yaml { name = "alice" });;
- : string = "name: custom-alice\n"
There is a ~skip_unknown
flag for telling the deriver to simply ignore any fields which are missing. This is particularly useful when you only wish to partially decode a yaml value.
Consider the following yaml:
let yaml = "name: Bob\nage: 42\nmisc: We don't need this!"
If we try to do the normal decoding of this but only partially extract the fields, it will throw an error.
# type t = {
name : string;
age : int;
}[@@deriving of_yaml];;
type t = { name : string; age : int; }
val of_yaml :
[> `O of (string * [> `Float of float | `String of string ]) list ] ->
(t, [> `Msg of string ]) result = <fun>
# Yaml.of_string_exn yaml |> of_yaml;;
- : (t, [> `Msg of string ]) result =
Error (`Msg "Failed to find the case for: misc")
Instead we tell the deriver to ignore unknown fields.
type t = {
name : string;
age : int;
}[@@deriving of_yaml ~skip_unknown]
# Yaml.of_string_exn yaml |> of_yaml;;
- : (t, [> `Msg of string ]) result = Ok {name = "Bob"; age = 42}
One important thing is that 'a option
values within records will return None
if the Yaml you are trying to convert does not exist.
OCaml Type | Yaml Type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|