LibYAML binding for Lua.
LYAML binds LibYAML to LuaJIT and Lua 5.1 through 5.5, for reading and writing YAML 1.1:
lyaml.load turns a YAML stream into Lua tables, and
lyaml.dump turns Lua tables back into YAMLlyaml.null keeps YAML’s nulls, which Lua tables can’t
hold as nilThe API reference has every function in detail.
Install the latest release with LuaRocks:
luarocks install lyamlLYAML needs LibYAML and its headers, which most systems package as
libyaml-dev or libyaml. If LuaRocks can’t find them, say where
they are:
luarocks install lyaml YAML_DIR=/opt/homebrewWithout LuaRocks, build and install it with Luke, from a clone of the repository:
build-aux/luke YAML_DIR=/opt/homebrew
sudo build-aux/luke PREFIX=/usr/local installlyaml.load returns the first document of a YAML stream as a Lua
value:
local lyaml = require 'lyaml'
lyaml.load 'foo: bar'
--> {foo = 'bar'}A mapping becomes a table with those keys, and a sequence a list. With
all = true in its second argument, load returns a list of every
document in the stream instead:
local stream = [[
--- one
...
--- two
...
]]
lyaml.load(stream) --> 'one'
lyaml.load(stream, {all = true}) --> {'one', 'two'}An alias loads as the table its anchor names, so after
local t = lyaml.load 'base: &b {x: 1}\nother: *b't.base == t.other. Anchors are local to the document they are in.
load raises an error for a stream that LibYAML can’t parse, or a
value that does not suit its tag, with the line and column where it
found the problem:
lyaml.load 'a: !!int nope'
--> error: 1:4: invalid 'tag:yaml.org,2002:int' value: 'nope'lyaml.dump takes a list of documents, and returns a YAML stream with
each of them in turn. To dump one table, put it in a list of its own:
lyaml.dump { {foo = 'bar'} }
--> ---
--> foo: bar
--> ...
lyaml.dump {'one', 'two'}
--> --- one
--> ...
--> --- two
--> ...A table whose keys are exactly 1, 2, 3 and so on is dumped as a
sequence, and any other table as a mapping, in the order that pairs
returns its keys. A string with a newline is dumped as a literal
block, and a string that would load as something else, such as '42'
or 'yes', is quoted, so that it loads as a string again. dump
raises an error for a function, userdata or thread.
The anchors field of the second argument maps anchor names to tables
that the documents contain. dump writes such a table with its
anchor the first time it reaches it, and as an alias after that:
local base = {x = 1}
lyaml.dump({ {a = base, b = base} }, {anchors = {base = base}})
--> ---
--> a: &base
--> x: 1
--> b: *base
--> ...A Lua table can’t hold a key whose value is nil, but a YAML mapping
can have a key whose value is null. So load returns YAML’s null,
written ~, null or nothing at all, as lyaml.null, and dump
writes lyaml.null as ~:
local t = lyaml.load 'a: ~'
t.a == lyaml.null --> true
lyaml.dump {t}
--> ---
--> a: ~
--> ...lyaml.null is a value to compare with, not a function to call.
A plain scalar, without quotes or a tag, is converted by the content
it has: 1 loads as a number, yes as true, ~ as lyaml.null,
and so on. The functions in lyaml.implicit each try one conversion,
and return nil for a value they don’t recognise:
| Function | Recognises |
|---|---|
null |
~, null, Null, NULL and nothing |
bool |
true/false, yes/no and on/off, in lower, capitalised or upper case |
octal |
012 |
decimal |
12345 |
float |
1e-3, -0.12 |
inf, nan |
.inf, -.inf, .nan |
hexadecimal |
0xdeadbeef |
binary |
0b1010_0111 |
sexagesimal |
190:20:30 |
sexfloat |
190:20:30.15 |
By default, load tries them all, and leaves the value as a string if
none of them recognises it. Pass your own function in the
implicit_scalar field of the second argument to choose differently,
such as with anyof from lyaml.functional, which tries each function
in turn and returns the first result that is not nil:
local functional = require 'lyaml.functional'
local implicit = require 'lyaml.implicit'
-- Only nulls and decimals; yes, 0x1f and the rest stay strings.
local strict = functional.anyof {
implicit.null,
implicit.decimal,
functional.id,
}
lyaml.load('a: yes\nb: 10', {implicit_scalar = strict})
--> {a = 'yes', b = 10}Pass the same function to dump too, so that it quotes only the strings
that function would convert when they are loaded again.
A scalar with a tag is converted by the function for that tag in the
explicit_scalar field instead, a table keyed by the full tag name.
The default has the functions from lyaml.explicit for
tag:yaml.org,2002:bool, float, int, null and str, which
raise an error for a value that does not suit the tag.
The yaml module is the C binding to LibYAML that lyaml is built on.
yaml.parser returns an iterator over the events of a YAML stream,
each a table with a type, the start_mark and end_mark of where it
is in the stream, and the other fields of that event, such as the
value, anchor, tag and style of a scalar:
local yaml = require 'yaml'
for event in yaml.parser 'a: [1, b]' do
print(event.type)
end
--> STREAM_START, DOCUMENT_START, MAPPING_START, SCALAR,
--> SEQUENCE_START, SCALAR, SCALAR, SEQUENCE_END, MAPPING_END,
--> DOCUMENT_END, STREAM_ENDThat is the “parse” step of the “parse, compose, construct” model of
the YAML 1.1 specification, with every detail of the stream
that load leaves out, such as line and column numbers. yaml.scanner
returns an iterator over the tokens of the stream instead, one step
lower: see LibYAML’s yaml.h for what each one holds.
yaml.emitter goes the other way. Its emit function takes one event
table at a time, and the STREAM_END event returns true and the
stream:
local emitter = yaml.emitter()
emitter.emit {type = 'STREAM_START'}
emitter.emit {type = 'DOCUMENT_START'}
emitter.emit {type = 'SCALAR', value = 'hi'}
emitter.emit {type = 'DOCUMENT_END'}
local ok, stream = emitter.emit {type = 'STREAM_END'}
--> stream == '--- hi\n...\n'Please report bugs and make suggestions as GitHub issues, and check that they are not already fixed on master first. Pull requests are especially welcome.