/ppx_deriving_yaml

OCaml types to Yaml types and back again

Primary LanguageOCamlISC LicenseISC

Ppx_deriving_yaml -- OCaml types to YAML types

This ppx is based on ppx_yojson and ppx_deriving_yojson because of the many similarities between json and yaml. In particular many of the semantics of OCaml types <-> Yaml types are the same as those implemented by the Yojson ppx.

This is a small ppx deriver that lets you convert your OCaml types to yaml ones. This means you can describe yaml structures in OCaml and easily convert them to yaml.

Usage

The usage docs are linked to what has been implemented from the checklist

For converting OCaml types to Yaml types 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 which is compatible with the Ezjsonm.value type.

of_yaml produces OCaml types wrapped in a result -- this is how ocaml-yaml also handles errors i.e. not using exceptions. Based on your type this should let you move between yaml and OCaml types.

Here is a small example.

type person = { name : string; age : int } [@@deriving yaml]
type users = person list [@@deriving yaml]

This will produce four functions.

val person_to_yaml : person -> Yaml.value 
val person_of_yaml : Yaml.value -> (person, [> `Msg of string ]) result 
val users_to_yaml : users -> Yaml.value 
val users_of_yaml : Yaml.value -> (users, [> `Msg of string ]) result 

If you make polymorphic types, then you will have to supply the function to convert the unknown to a yaml value. For example:

type 'a note = { txt : 'a } [@@deriving yaml]

produces the following function.

val note_to_yaml : ('a -> Yaml.value) -> 'a note -> [> `O of (string * Yaml.value) list ]

Implementation Details

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
int `Float
float `Float
string `String
bool `Bool
None `Null
list `A []
array `A []
record e.g { name : string } `O [("name", `String s)]
A of int or [`A of int] `O [("A", `A [`Float f])]

Optional Attributes

OCaml has constraints on the shape that certain words in the syntax can take. For example, 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.

For example:

type t = {
  camel_name : string [@key "camel-name"]
}

Will produce Yaml of the form

camel-name: <string>

Checklist

  • Simples types (int, list, records...) to Yaml.value types
  • Yaml.value interface types
  • Yaml.value types to OCaml types i.e. of_yaml
  • More complex types (parametric polymorphic ones) to any of the Yaml types
  • Design and implement how variants should be handled
  • Better interface support i.e. .mli files
  • Simple types (int, list, records...) to Yaml.yaml types