mirror of https://github.com/status-im/NimYAML.git
483 lines
9.8 KiB
Plaintext
483 lines
9.8 KiB
Plaintext
=======
|
|
NimYAML
|
|
=======
|
|
|
|
Introduction
|
|
============
|
|
|
|
**NimYAML** is a pure YAML implementation for Nim. It is able to read from and
|
|
write to YAML character streams, and to serialize from and construct to native
|
|
Nim types. It exclusively supports
|
|
`YAML 1.2 <#http://www.yaml.org/spec/1.2/spec.html>`_.
|
|
|
|
Source code can be found on `GitHub <https://github.com/flyx/NimYAML>`_. You can
|
|
install it with `Nimble <https://github.com/nim-lang/nimble>`_:
|
|
|
|
.. code-block:: bash
|
|
nimble install yaml
|
|
|
|
Quickstart
|
|
==========
|
|
|
|
Dumping Nim objects as YAML
|
|
--------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>out.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Person = object
|
|
name : string
|
|
age : int32
|
|
|
|
var personList = newSeq[Person]()
|
|
personList.add(Person(name: "Karl Koch", age: 23))
|
|
personList.add(Person(name: "Peter Pan", age: 12))
|
|
|
|
var s = newFileStream("out.yaml", fmWrite)
|
|
dump(personList, s)
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td>
|
|
<td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.2
|
|
--- !nim:system:seq(nim:custom:Person)
|
|
-
|
|
name: Karl Koch
|
|
age: 23
|
|
-
|
|
name: Peter Pan
|
|
age: 12
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Loading Nim objects from YAML
|
|
----------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>in.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Person = object
|
|
name : string
|
|
age : int32
|
|
|
|
var personList: seq[Person]
|
|
var s = newFileStream("in.yaml")
|
|
load(s, personList)
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td>
|
|
<td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.2
|
|
---
|
|
- { name: Karl Koch, age: 23 }
|
|
- { name: Peter Pan, age: 12 }
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Customizing output style
|
|
----------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>out.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Person = object
|
|
name: string
|
|
age: int32
|
|
|
|
var personList: seq[Person]
|
|
personList.add(Person(name: "Karl Koch", age: 23))
|
|
personList.add(Person(name: "Peter Pan", age: 12))
|
|
|
|
var s = newFileStream("out.yaml")
|
|
dump(personList, s, options = defineOptions(
|
|
style = psCanonical,
|
|
indentationStep = 3,
|
|
newlines = nlLF,
|
|
outputVersion = ov1_1))
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td><td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.1
|
|
--- !nim:system:seq(nim:custom:Person)
|
|
[
|
|
!nim:custom:Person {
|
|
? !!str "name"
|
|
: !!str "Karl Koch",
|
|
? !!str "age"
|
|
: !nim:system:int32 "23"
|
|
},
|
|
!nim:custom:Person {
|
|
? !!str "name"
|
|
: !!str "Peter Pan",
|
|
? !!str "age"
|
|
: !nim:system:int32 "12"
|
|
}
|
|
]
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Dumping reference types and cyclic structures
|
|
---------------------------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>out.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type
|
|
Node = ref NodeObj
|
|
NodeObj = object
|
|
name: string
|
|
left, right: Node
|
|
|
|
var node1, node2, node3: Node
|
|
new(node1); new(node2); new(node3)
|
|
node1.name = "Node 1"
|
|
node2.name = "Node 2"
|
|
node3.name = "Node 3"
|
|
node1.left = node2
|
|
node1.right = node3
|
|
node2.right = node3
|
|
node3.left = node1
|
|
|
|
var s = newFileStream("out.yaml", fmWrite)
|
|
dump(node1, s)
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td><td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.2
|
|
--- !nim:custom:NodeObj &a
|
|
name: Node 1
|
|
left:
|
|
name: Node 2
|
|
left: !!null ~
|
|
right: &b
|
|
name: Node 3
|
|
left: *a
|
|
right: !!null ~
|
|
right: *b
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Loading reference types and cyclic structures
|
|
---------------------------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>in.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type
|
|
Node = ref NodeObj
|
|
NodeObj = object
|
|
name: string
|
|
left, right: Node
|
|
|
|
var node1: Node
|
|
|
|
var s = newFileStream("in.yaml")
|
|
load(s, node1)
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td><td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.2
|
|
--- !nim:custom:NodeObj &a
|
|
name: Node 1
|
|
left:
|
|
name: Node 2
|
|
left: ~
|
|
right: &b
|
|
name: Node 3
|
|
left: *a
|
|
right: ~
|
|
right: *b
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Defining a custom tag uri for a type
|
|
------------------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>out.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Mob = object
|
|
level, experience: int32
|
|
drops: seq[string]
|
|
|
|
setTagUri(Mob, "!Mob")
|
|
setTagUri(seq[string], "!Drops")
|
|
|
|
var mob = Mob(level: 42, experience: 1800, drops:
|
|
@["Sword of Mob Slaying"])
|
|
var s = newFileStream("out.yaml", fmWrite)
|
|
dump(mob, s,
|
|
options = defineOptions(tagStyle = tsAll))
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td><td>
|
|
|
|
.. code-block:: yaml
|
|
YAML 1.2
|
|
--- !Mob
|
|
!nim:field level: !nim:system:int32 42
|
|
!nim:field experience: !nim:system:int32 1800
|
|
!nim:field drops: !Drops [!!str Sword of Mob Slaying]
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Dumping Nim objects as JSON
|
|
---------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>out.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Person = object
|
|
name : string
|
|
age : int32
|
|
|
|
var personList = newSeq[Person]()
|
|
personList.add(Person(name: "Karl Koch", age: 23))
|
|
personList.add(Person(name: "Peter Pan", age: 12))
|
|
|
|
var s = newFileStream("out.yaml", fmWrite)
|
|
dump(personList, s,
|
|
options = defineOptions(style = psJson))
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td>
|
|
<td>
|
|
|
|
.. code-block:: yaml
|
|
[
|
|
{
|
|
"name": "Karl Koch",
|
|
"age": 23
|
|
},
|
|
{
|
|
"name": "Peter Pan",
|
|
"age": 12
|
|
}
|
|
]
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Loading Nim objects from JSON
|
|
-----------------------------
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>in.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Person = object
|
|
name : string
|
|
age : int32
|
|
|
|
var personList: seq[Person]
|
|
|
|
var s = newFileStream("in.yaml")
|
|
load(s, personList)
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td>
|
|
<td>
|
|
|
|
.. code-block:: yaml
|
|
[
|
|
{
|
|
"name": "Karl Koch",
|
|
"age": 23
|
|
},
|
|
{
|
|
"name": "Peter Pan",
|
|
"age": 12
|
|
}
|
|
]
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
Processing a Sequence of Heterogeneous Items
|
|
--------------------------------------------
|
|
|
|
… With variant objects
|
|
......................
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>in.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type
|
|
Person = object
|
|
name: string
|
|
|
|
ContainerKind = enum
|
|
ckString, ckInt, ckBool, ckPerson, ckNone
|
|
|
|
Container = object
|
|
case kind: ContainerKind
|
|
of ckString:
|
|
strVal: string
|
|
of ckInt:
|
|
intVal: int
|
|
of ckBool:
|
|
boolVal: bool
|
|
of ckPerson:
|
|
personVal: Person
|
|
of ckNone:
|
|
discard
|
|
|
|
setTagUri(Person, "!nim:demo:Person")
|
|
|
|
# tell NimYAML to use Container as implicit type.
|
|
# only possible with variant object types where
|
|
# each branch contains at most one object.
|
|
markAsImplicit(Container)
|
|
|
|
var list: seq[Container]
|
|
|
|
var s = newFileStream("in.yaml")
|
|
load(s, list)
|
|
s.close()
|
|
|
|
assert(list[0].kind == ckString)
|
|
assert(list[0].strVal == "this is a string")
|
|
# and so on
|
|
|
|
.. raw:: html
|
|
</td>
|
|
<td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.2
|
|
---
|
|
- this is a string
|
|
- 42
|
|
- false
|
|
- !!str 23
|
|
- !nim:demo:Person {name: Trillian}
|
|
- !!null
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table>
|
|
|
|
… With the Sequential API
|
|
.........................
|
|
|
|
.. raw:: html
|
|
<table class="quickstart-example"><thead><tr><th>code.nim</th>
|
|
<th>in.yaml</th></tr></thead><tbody><tr><td>
|
|
|
|
.. code-block:: nim
|
|
import yaml
|
|
type Person = object
|
|
name: string
|
|
|
|
setTagUri(Person, "!nim:demo:Person", yTagPerson)
|
|
|
|
var
|
|
s = newFileStream("in.yaml", fmRead)
|
|
context = newConstructionContext()
|
|
parser = newYamlParser(serializationTagLibrary)
|
|
events = parser.parse(s)
|
|
|
|
assert events.next().kind == yamlStartDoc
|
|
assert events.next().kind == yamlStartSeq
|
|
var nextEvent = events.peek()
|
|
while nextEvent.kind != yamlEndSeq:
|
|
var curTag = nextEvent.tag()
|
|
if curTag == yTagQuestionMark:
|
|
# we only support implicitly tagged scalars
|
|
assert nextEvent.kind == yamlScalar
|
|
case guessType(nextEvent.scalarContent)
|
|
of yTypeInteger: curTag = yTagInteger
|
|
of yTypeBoolTrue, yTypeBoolFalse:
|
|
curTag = yTagBoolean
|
|
of yTypeUnknown: curTag = yTagString
|
|
else: assert false, "Type not supported!"
|
|
elif curTag == yTagExclamationMark:
|
|
curTag = yTagString
|
|
case curTag
|
|
of yTagString:
|
|
var s: string
|
|
events.constructChild(context, s)
|
|
echo "got string: ", s
|
|
of yTagInteger:
|
|
var i: int32
|
|
events.constructChild(context, i)
|
|
echo "got integer: ", i
|
|
of yTagBoolean:
|
|
var b: bool
|
|
events.constructChild(context, b)
|
|
echo "got boolean: ", b
|
|
of yTagPerson:
|
|
var p: Person
|
|
events.constructChild(context, p)
|
|
echo "got Person with name: ", p.name
|
|
else: assert false, "unsupported tag: " & $curTag
|
|
nextEvent = events.peek()
|
|
assert events.next().kind == yamlEndSeq
|
|
assert events.next().kind == yamlEndDoc
|
|
assert events.finished()
|
|
s.close()
|
|
|
|
.. raw:: html
|
|
</td>
|
|
<td>
|
|
|
|
.. code-block:: yaml
|
|
%YAML 1.2
|
|
--- !!seq
|
|
- this is a string
|
|
- 42
|
|
- false
|
|
- !!str 23
|
|
- !nim:demo:Person {name: Trillian}
|
|
|
|
.. raw:: html
|
|
</td></tr></tbody></table> |