Giter VIP home page Giter VIP logo

ppx_deriving_yaml's Introduction

ppx_deriving_yaml

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 way the OCaml values are encoded to yaml types are the same as those implemented by the Yojson ppx.

Basic Usage

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 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 values.

# #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 * Yaml.value) list ] list ] ->
    (person list, [> `Msg of string ]) result
= <fun>

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.

# 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>

Attributes

Key and Name

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"]
}[@@deriving to_yaml]

Will produce Yaml of the form

# Yaml.to_string (to_yaml { camel_name = "Alice" });;
- : string Yaml.res = Ok "camel-name: Alice\n"

Default Values

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}

Custom encoding and decoding

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 = {
  age : int [@to_yaml fun i -> `Float (float_of_int (i + 1))]
}[@@deriving yaml]

The to_yaml function will use the custom encoder now instead.

# Yaml.to_string (to_yaml { age = 41 });;
- : string Yaml.res = Ok "age: 42\n"

Partially Decoding

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 yaml]

Note that the error is often rather confusing. There is room for improvement (PRs welcome!).

# Yaml.of_string_exn yaml |> of_yaml;;
- : (t, [> `Msg of string ]) result =
Error (`Msg "miscWe don't need this!\n")

Instead we tell the deriver to ignore unknown fields.

type t = {
  name : string;
  age : int;
}[@@deriving yaml ~skip_unknown]
# Yaml.of_string_exn yaml |> of_yaml;;
- : (t, [> `Msg of string ]) result = Ok {name = "Bob"; age = 42}

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])]

ppx_deriving_yaml's People

Contributors

maurobringolf avatar patricoferris avatar prosper74 avatar

Forkers

marrious11

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.