package otoml

  1. Overview
  2. Docs
TOML parsing, manipulation, and pretty-printing library (1.0.0-compliant)

Install

Dune Dependency

Authors

Maintainers

Sources

0.9.0.tar.gz
md5=ef9947d298d0300f4201343b05392807
sha512=ae53d8f58fce8efc6d22b1963b149e5421c81ce501cab6d0a6dcdf91921d4d3cc40213a97c265f6c94cfb4ff957aa9e9633cada799e8645533808d0ca38ce136

Description

OTOML is a library for parsing, manipulating, and pretty-printing TOML files.

  • Fully 1.0.0-compliant.
  • No extra dependencies: default implementation uses native numbers and represents dates as strings.
  • Provides a functor for building alternative implementations: plug your own bignum and calendar libraries if required.
  • Informative parse error reporting.
  • Pretty-printer offers flexible indentation options.

Published: 16 Jul 2021

README

OTOML

A TOML parsing and manipulation library for OCaml.

In short:

  • TOML 1.0-compliant.

  • Transparent (no abstract types).

  • Preserves original concrete syntax (e.g. inline vs normal table) when parsing and printing.

  • Flexible pretty-printing options.

  • Does not force a calendar library dependency on you (you can plug your own into the functor).

Goals

The main goal for writing another TOML library is to provide a library for manipulating TOML files, not just reading them.

TOML is designed as a configuration file format. It's not just a serialization format for machines to talk to one another. A lot of time it's written, edited, and read by humans.

That is why TOML supports comments and multiple ways to write the same data.

Ideally, when a program reads a TOML file and writes it back, it should be able to echo it back and respect user's choice of using inline records vs sections (i.e. section = {...} vs [section]) and so on.

OTOML preserves that information and makes it available to the user.

It also offers a convenient interface for accessing and modifying values in deeply nested tables.

Example

(* Parse a TOML string. *)

utop # let t = Otoml.Parser.from_string "
[settings]
  [settings.basic]
    crash_randomly = true
" ;;
val t : Otoml.t =
  Otoml.TomlTable
   [("settings",
     Otoml.TomlTable
      [("basic", Otoml.TomlTable [("crash_randomly", Otoml.TomlBoolean true)])])]

(* Look up a deeply nested value with a known type. *)
utop # Otoml.find Otoml.get_boolean t ["settings"; "basic"; "crash_randomly"] ;;
- : bool = true

(* Update a deeply nested value. *)
utop # let t = Otoml.update t ["settings"; "basic"; "crash_randomly"] (Some (Otoml.TomlInteger 0)) ;;
val t : Otoml.t =
  Otoml.TomlTable
   [("settings",
     Otoml.TomlTable
      [("basic", Otoml.TomlTable [("crash_randomly", Otoml.TomlInteger 0)])])]

(* Look up a value and convert it to desired type (if possible). *)
utop # Otoml.find (Otoml.get_boolean ~strict:false) t ["settings"; "basic"; "crash_randomly"] ;;
- : bool = false

(* There's a pretty-printer, too! *)
utop # let t = Otoml.Parser.from_string "[foo] \n [foo.bar] \n baz = {quux = false} \n xyzzy = [ ] \n" |>
  Otoml.Printer.to_channel ~indent_width:4 ~indent_subtables:true ~collapse_tables:true stdout ;;

[foo.bar]
    baz = {quux = false}
    xyzzy = []

val t : unit = ()

Plugging your own dependencies

The default implementation is provided for convenience: it represents integer and floating point numbers with OCaml's native int and float types, and stores date/time values as strings that you can parse with your favorite calendar library.

However, it's not hardcoded but built with an OCaml functor. This is how you could assemble the default implementation yourself.

module DefaultToml = Otoml.Base.Make (Otoml.Base.NativeInteger) (Otoml.Base.NativeFloat) (Otoml.Base.StringDate)

Thus you can replace any of the modules or all of them with your own. For example, this is how you can use zarith for a big integer implementation but keep native floats and simple string dates:

(* No signature ascription:
   `module BigInteger : Otoml.Base.TomlInteger` would make the type t abstract,
   which is inconvenient.
 *)
module BigInteger = struct
  type t = Z.t
  let of_string = Z.of_string
  let to_string = Z.to_string
  let of_boolean b = if b then Z.one else Z.zero
  let to_boolean n = (n <> Z.zero)
end

module MyToml = Otoml.Base.Make (BigInteger) (Otoml.Base.OCamlFloat) (Otoml.Base.StringDate)

Deviations from the TOML 1.0 specification

OTOML uses OCaml's native integer type, which is 63-bit on 64-bit architectures and 31-bit on 32-bit ones.

The default implementation does not interpret datetime values at all, only checks them for superficial validity and returns as strings. (e.g. 1993-09-947 is considered invalid, but 1993-02-29 is valid despite the fact that 1993 wasn't a leap year).

Thus, actual precision depends on the library you use to parse those date strings or plug into the functor.

Dependencies (5)

  1. uutf >= "1.0.0"
  2. dune >= "2.0.0"
  3. menhirLib >= "20200525"
  4. menhir
  5. ocaml >= "4.08.0"

Dev Dependencies

None

Used by (2)

  1. lab
  2. soupault >= "3.0.0" & < "3.2.1"

Conflicts

None