Module

tome

src/tome.pooka

Read TOML 1.0, the configuration format that tries hard to be obvious.

A document becomes a Toml value: a table at the top, holding strings, numbers, booleans, dates, arrays and more tables. Take it apart with match, or with the helpers at the end of this module.

Pooka
import tome

main() {
  let text = "name = \"night_library\"\n\n[owner]\nname = \"Ada\"\n"
  let assert Ok(config) = tome.parse(text)
  echo tome.path(config, ["owner", "name"])
}

Tables keep their keys in the order they were written.

API reference

class

Toml

src/tome.pooka:31
class Toml

Any TOML value.

class

TString

src/tome.pooka:34
class TString(value: String) is Toml

A string, with its escapes already resolved.

field

value

src/tome.pooka:34
value: String
INFERREDString
constructor

new

src/tome.pooka:34
INFERREDfn(String) -> tome.TString
class

TInt

src/tome.pooka:37
class TInt(value: Int) is Toml

A whole number, written in decimal, hexadecimal, octal or binary.

field

value

src/tome.pooka:37
value: Int
INFERREDInt
constructor

new

src/tome.pooka:37
INFERREDfn(Int) -> tome.TInt
class

TFloat

src/tome.pooka:40
class TFloat(value: Float) is Toml

A number with a fraction or an exponent.

field

value

src/tome.pooka:40
value: Float
INFERREDFloat
constructor

new

src/tome.pooka:40
INFERREDfn(Float) -> tome.TFloat
class

TInfinity

src/tome.pooka:43
class TInfinity(positive: Bool) is Toml

inf, +inf or -inf.

field

positive

src/tome.pooka:43
positive: Bool
INFERREDBool
constructor

new

src/tome.pooka:43
INFERREDfn(Bool) -> tome.TInfinity
class

TNan

src/tome.pooka:46
class TNan is Toml

nan, the float that is not a number.

class

TBool

src/tome.pooka:49
class TBool(value: Bool) is Toml

true or false.

field

value

src/tome.pooka:49
value: Bool
INFERREDBool
constructor

new

src/tome.pooka:49
INFERREDfn(Bool) -> tome.TBool
class

TDateTime

src/tome.pooka:53
class TDateTime(value: String) is Toml

A date with a time, with or without an offset, as it was written: 1979-05-27T07:32:00Z. A space between the date and the time becomes T.

field

value

src/tome.pooka:53
value: String
INFERREDString
constructor

new

src/tome.pooka:53
INFERREDfn(String) -> tome.TDateTime
class

TDate

src/tome.pooka:56
class TDate(value: String) is Toml

A date on its own: 1979-05-27.

field

value

src/tome.pooka:56
value: String
INFERREDString
constructor

new

src/tome.pooka:56
INFERREDfn(String) -> tome.TDate
class

TTime

src/tome.pooka:59
class TTime(value: String) is Toml

A time on its own: 07:32:00.

field

value

src/tome.pooka:59
value: String
INFERREDString
constructor

new

src/tome.pooka:59
INFERREDfn(String) -> tome.TTime
class

TArray

src/tome.pooka:63
class TArray(items: List(Toml)) is Toml

An array. An array of tables, [[name]], is an array whose items are tables.

field

items

src/tome.pooka:63
items: List(Toml)
INFERREDList(tome.Toml)
constructor

new

src/tome.pooka:63
INFERREDfn(List(tome.Toml)) -> tome.TArray
class

TTable

src/tome.pooka:66
class TTable(entries: List(#(String, Toml))) is Toml

A table, as its entries in the order they were written.

field

entries

src/tome.pooka:66
entries: List(#(String, Toml))
INFERREDList(#(String, tome.Toml))
constructor

new

src/tome.pooka:66
INFERREDfn(List(#(String, tome.Toml))) -> tome.TTable
class

TomlError

src/tome.pooka:69
class TomlError(line: Int, message: String)

Why a text is not TOML, and the line where the trouble was noticed.

field

line

src/tome.pooka:69
line: Int
INFERREDInt
field

message

src/tome.pooka:69
message: String
INFERREDString
constructor

new

src/tome.pooka:69
INFERREDfn(Int, String) -> tome.TomlError
function

parse

src/tome.pooka:79
parse(text: String) -> Result(Toml, TomlError)
INFERREDfn(String) -> Result(tome.Toml, tome.TomlError)

Read a TOML document. The result is always a TTable.

Pooka
import tome

assert tome.parse("answer = 42") == Ok(tome.TTable([#("answer", tome.TInt(42))]))
assert tome.parse("answer = ") == Error(tome.TomlError(1, "a value is missing"))
function

parse_bytes

src/tome.pooka:92
parse_bytes(input: BitArray) -> Result(Toml, TomlError)
INFERREDfn(BitArray) -> Result(tome.Toml, tome.TomlError)

Read a document from bytes, rejecting invalid UTF-8 before opening a table. This is useful with file.read_bytes, where decoding has not happened yet.

Pooka
import tome

assert tome.parse_bytes(<<110, 32, 61, 32, 49>>) == tome.parse("n = 1")
let assert Error(_) = tome.parse_bytes(<<255>>)
function

describe

src/tome.pooka:124
describe(problem: TomlError) -> String
INFERREDfn(tome.TomlError) -> String

A sentence for the person who wrote the file.

Pooka
import tome

assert tome.describe(tome.TomlError(3, "a value is missing")) == "line 3: a value is missing"
function

get

src/tome.pooka:139
get(value: Toml, key: String) -> Option(Toml)
INFERREDfn(tome.Toml, String) -> Option(tome.Toml)

The value under a key, if this is a table that has it.

Pooka
import tome

let assert Ok(config) = tome.parse("name = \"Ada\"")
assert tome.get(config, "name") == Some(tome.TString("Ada"))
assert tome.get(config, "wings") == None
function

path

src/tome.pooka:154
path(value: Toml, keys: List(String)) -> Option(Toml)
INFERREDfn(tome.Toml, List(String)) -> Option(tome.Toml)

Follow several keys, one table inside another.

Pooka
import tome

let assert Ok(config) = tome.parse("[owner]\nname = \"Ada\"")
assert tome.path(config, ["owner", "name"]) == Some(tome.TString("Ada"))
function

at

src/tome.pooka:173
at(value: Toml, index: Int) -> Option(Toml)
INFERREDfn(tome.Toml, Int) -> Option(tome.Toml)

The item at a position, counting from zero, if this is an array that has it. Negative and out-of-range positions return None.

Pooka
let assert Ok(config) = tome.parse("birds = ['owl', 'crow']")
let assert Some(birds) = tome.get(config, "birds")
assert tome.at(birds, 1) == Some(tome.TString("crow"))
assert tome.at(birds, -1) == None
function

as_string

src/tome.pooka:186
as_string(value: Toml) -> Option(String)
INFERREDfn(tome.Toml) -> Option(String)

The text, if this is a string.

Pooka
assert tome.as_string(tome.TString("owl")) == Some("owl")
assert tome.as_string(tome.TInt(2)) == None
function

as_int

src/tome.pooka:198
as_int(value: Toml) -> Option(Int)
INFERREDfn(tome.Toml) -> Option(Int)

The number, if this is a whole number.

Pooka
assert tome.as_int(tome.TInt(42)) == Some(42)
function

as_float

src/tome.pooka:212
as_float(value: Toml) -> Option(Float)
INFERREDfn(tome.Toml) -> Option(Float)

The number, if this is a float. Whole numbers are not floats in TOML. Infinity and NaN have their own value classes; they do not become BEAM floats.

Pooka
assert tome.as_float(tome.TFloat(1.5)) == Some(1.5)
assert tome.as_float(tome.TInt(1)) == None
function

as_bool

src/tome.pooka:224
as_bool(value: Toml) -> Option(Bool)
INFERREDfn(tome.Toml) -> Option(Bool)

The truth value, if this is true or false.

Pooka
assert tome.as_bool(tome.TBool(True)) == Some(True)
function

as_datetime

src/tome.pooka:237
as_datetime(value: Toml) -> Option(String)
INFERREDfn(tome.Toml) -> Option(String)

The text of a date, a time, or a date with a time. Fractional precision and offsets stay as written. A space between the date and time becomes T.

Pooka
assert tome.as_datetime(tome.TDate("2024-02-29")) == Some("2024-02-29")
function

as_list

src/tome.pooka:251
as_list(value: Toml) -> Option(List(Toml))
INFERREDfn(tome.Toml) -> Option(List(tome.Toml))

The items, if this is an array.

Pooka
assert tome.as_list(tome.TArray([])) == Some([])
function

as_entries

src/tome.pooka:267
as_entries(value: Toml) -> Option(List(#(String, Toml)))
INFERREDfn(tome.Toml) -> Option(List(#(String, tome.Toml)))

The entries, if this is a table, in their source order.

Pooka
let assert Ok(config) = tome.parse("z = 1\na = 2")
let assert Some(entries) = tome.as_entries(config)
assert list.map(entries, fn(entry) { let #(key, _) = entry
  key
}) == ["z", "a"]