======= 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 `_. You can install it with `Nimble `_: .. code-block:: bash nimble install nimyaml Quickstart ========== Dumping Nim objects as YAML -------------------------- .. raw:: html
code.nim out.yaml
.. 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 .. code-block:: yaml %YAML 1.2 --- !nim:system:seq(nim:custom:Person) - name: Karl Koch age: 23 - name: Peter Pan age: 12 .. raw:: html
Loading Nim objects from YAML ---------------------------- .. raw:: html
code.nim in.yaml
.. 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 .. code-block:: yaml %YAML 1.2 --- - { name: Karl Koch, age: 23 } - { name: Peter Pan, age: 12 } .. raw:: html
Customizing output style ---------------------- .. raw:: html
code.nim out.yaml
.. 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 .. 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
Dumping reference types and cyclic structures --------------------------------------------- .. raw:: html
code.nim out.yaml
.. 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 .. 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
Loading reference types and cyclic structures --------------------------------------------- .. raw:: html
code.nim in.yaml
.. 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 .. 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
Defining a custom tag uri for a type ------------------------------------ .. raw:: html
code.nim out.yaml
.. 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 .. 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
Dumping Nim objects as JSON --------------------------- .. raw:: html
code.nim out.yaml
.. 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 .. code-block:: yaml [ { "name": "Karl Koch", "age": 23 }, { "name": "Peter Pan", "age": 12 } ] .. raw:: html
Loading Nim objects from JSON ----------------------------- .. raw:: html
code.nim in.yaml
.. 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 .. code-block:: yaml [ { "name": "Karl Koch", "age": 23 }, { "name": "Peter Pan", "age": 12 } ] .. raw:: html
Processing a Sequence of Heterogeneous Items -------------------------------------------- … With variant objects ...................... .. raw:: html
code.nim in.yaml
.. 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 .. code-block:: yaml %YAML 1.2 --- - this is a string - 42 - false - !!str 23 - !nim:demo:Person {name: Trillian} - !!null .. raw:: html
… With the Sequential API ......................... .. raw:: html
code.nim in.yaml
.. 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 .. code-block:: yaml %YAML 1.2 --- !!seq - this is a string - 42 - false - !!str 23 - !nim:demo:Person {name: Trillian} .. raw:: html