doc: extracted examples to own files

This commit is contained in:
Felix Krause 2016-10-08 18:38:27 +02:00
parent 834c4b174a
commit 31ac201e41
25 changed files with 466 additions and 467 deletions

2
.gitignore vendored
View File

@ -17,4 +17,6 @@ libyaml.dylib
libyaml.so
bench/json
docout
doc/rstPreproc
doc/tmp.rst
yaml-dev-kit

View File

@ -20,17 +20,21 @@ task serializationTests, "Run serialization tests":
task documentation, "Generate documentation":
exec "mkdir -p docout"
withDir "doc":
exec r"nim c rstPreproc"
exec r"./rstPreproc -o:tmp.rst index.txt"
exec r"nim rst2html -o:../docout/index.html tmp.rst"
exec r"./rstPreproc -o:tmp.rst api.txt"
exec r"nim rst2html -o:../docout/api.html tmp.rst"
exec r"./rstPreproc -o:tmp.rst serialization.txt"
exec r"nim rst2html -o:../docout/serialization.html tmp.rst"
exec "cp docutils.css style.css testing.html processing.svg ../docout"
exec r"nim doc2 -o:docout/yaml.html --docSeeSrcUrl:https://github.com/flyx/NimYAML/blob/`git log -n 1 --format=%H` yaml"
# bash! ah-ah \\ savior of the universe
for file in listFiles("yaml"):
let packageName = file[5..^5]
exec r"nim doc2 -o:docout/yaml." & packageName &
".html --docSeeSrcUrl:https://github.com/flyx/NimYAML/blob/yaml/`git log -n 1 --format=%H` " &
file
exec r"nim rst2html -o:docout/index.html doc/index.txt"
exec r"nim rst2html -o:docout/api.html doc/api.txt"
exec r"nim rst2html -o:docout/serialization.html doc/serialization.txt"
exec "cp doc/docutils.css doc/style.css doc/testing.html doc/processing.svg docout"
setCommand "nop"
task bench, "Benchmarking":

View File

@ -0,0 +1,14 @@
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()

View File

@ -0,0 +1,5 @@
%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]

View File

@ -0,0 +1,13 @@
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()

View File

@ -0,0 +1,10 @@
[
{
"name": "Karl Koch",
"age": 23
},
{
"name": "Peter Pan",
"age": 12
}
]

View File

@ -0,0 +1,20 @@
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()

View File

@ -0,0 +1,11 @@
%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

View File

@ -0,0 +1,12 @@
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()

View File

@ -0,0 +1,8 @@
%YAML 1.2
--- !nim:system:seq(nim:custom:Person)
-
name: Karl Koch
age: 23
-
name: Peter Pan
age: 12

View File

@ -0,0 +1,8 @@
%YAML 1.2
---
- this is a string
- 42
- false
- !!str 23
- !nim:demo:Person {name: Trillian}
- !!null

View File

@ -0,0 +1,37 @@
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

View File

@ -0,0 +1,10 @@
[
{
"name": "Karl Koch",
"age": 23
},
{
"name": "Peter Pan",
"age": 12
}
]

View File

@ -0,0 +1,10 @@
import yaml
type Person = object
name : string
age : int32
var personList: seq[Person]
var s = newFileStream("in.yaml")
load(s, personList)
s.close()

View File

@ -0,0 +1,11 @@
%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

View File

@ -0,0 +1,12 @@
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()

View File

@ -0,0 +1,4 @@
%YAML 1.2
---
- { name: Karl Koch, age: 23 }
- { name: Peter Pan, age: 12 }

View File

@ -0,0 +1,9 @@
import yaml
type Person = object
name : string
age : int32
var personList: seq[Person]
var s = newFileStream("in.yaml")
load(s, personList)
s.close()

View File

@ -0,0 +1,16 @@
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()

View File

@ -0,0 +1,16 @@
%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"
}
]

View File

@ -0,0 +1,43 @@
{
"Dumping Nim objects as YAML": [
"dump-yaml", "out"
],
"Loading Nim objects from YAML": [
"load-yaml", "in"
],
"Customizing output style" : [
"outputstyle", "out"
],
"Dumping reference types and cyclic structures": [
"dump-reftypes", "out"
],
"Loading reference types and cyclic structures": [
"load-reftypes", "in"
],
"Defining a custom tag uri for a type": [
"customtag", "out"
],
"Dumping Nim objects as JSON": [
"dump-json", "out"
],
"Loading Nim objects from JSON": [
"load-json", "in"
],
"Processing a Sequence of Heterogeneous Items": {
"… With variant objects": [
"implicit-variant", "in"
],
"… With the Sequential API": [
"sequential-api", "in"
]
}
}

View File

@ -0,0 +1,7 @@
%YAML 1.2
--- !!seq
- this is a string
- 42
- false
- !!str 23
- !nim:demo:Person {name: Trillian}

View File

@ -0,0 +1,51 @@
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()

View File

@ -19,465 +19,4 @@ install it with `Nimble <https://github.com/nim-lang/nimble>`_:
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>
%examples/quickstart.json%/

127
doc/rstPreproc.nim Normal file
View File

@ -0,0 +1,127 @@
## This is a tool for preprocessing rst files. Lines starting with ``%`` will
## get substituted by nicely layouted included nim and yaml code.
##
## The syntax of substituted lines is ``'%' jsonfile '%' jsonpath``. *jsonfile*
## shall be the path to a JSON file. *jsonpath* shall be a path to some node in
## that JSON file.
##
## Usage:
##
## rstPreproc -o:path <infile>
##
## *path* is the output path. If omitted, it will be equal to infile with its
## suffix substituted by ``.rst``. *infile* is the source rst file.
import parseopt2, json, streams, tables, strutils, os
var
infile = ""
path: string = nil
for kind, key, val in getopt():
case kind
of cmdArgument:
if infile == "":
if key == "":
echo "invalid input file with empty name!"
quit 1
infile = key
else:
echo "Only one input file is supported!"
quit 1
of cmdLongOption, cmdShortOption:
case key
of "out", "o":
if isNil(path): path = val
else:
echo "Duplicate output path!"
quit 1
else:
echo "Unknown option: ", key
quit 1
of cmdEnd: assert(false) # cannot happen
if infile == "":
echo "Missing input file!"
quit 1
if isNil(path):
for i in countdown(infile.len - 1, 0):
if infile[i] == '.':
if infile[i..^1] == ".rst": path = infile & ".rst"
else: path = infile[0..i] & "rst"
break
if isNil(path): path = infile & ".rst"
var tmpOut = newFileStream(path, fmWrite)
proc append(s: string) =
tmpOut.writeLine(s)
proc gotoPath(root: JsonNode, path: string): JsonNode =
doAssert path[0] == '/'
if path.len == 1: return root
doAssert root.kind == JObject
for i in 1..<path.len:
if path[i] == '/':
return gotoPath(root.getFields()[path[1..<i]], path[i+1 .. ^1])
return root.getFields()[path[1..^1]]
const headingChars = ['-', '`', ':', '\'']
proc outputExamples(node: JsonNode, prefix: string, level: int = 0) =
case node.kind
of JObject:
for key, value in node.getFields():
append(key)
let headingChar = if level >= headingChars.len: headingChars[^1] else:
headingChars[level]
append(repeat(headingChar, key.len) & '\l')
outputExamples(value, prefix, level + 1)
of JArray:
let elems = node.getElems()
case elems.len
of 2:
append(".. raw:: html")
append(" <table class=\"quickstart-example\"><thead><tr><th>code.nim</th>")
append(" <th>" & elems[1].getStr() &
".yaml</th></tr></thead><tbody><tr><td>\n")
append(".. code:: nim")
append(" :file: " & prefix & elems[0].getStr() & ".nim\n")
append(".. raw:: html")
append(" </td>\n <td>\n")
append(".. code:: yaml")
append(" :file: " & prefix & elems[0].getStr() & '.' &
elems[1].getStr() & ".yaml\n")
append(".. raw:: html")
append(" </td></tr></tbody></table>\n")
else:
echo "Unexpected number of elements in array: ", elems.len
quit 1
else:
echo "Unexpected node kind: ", node.kind
quit 1
var lineNum = 0
for line in infile.lines():
if line.len > 0 and line[0] == '%':
var
jsonFile: string = nil
jsonPath: string = nil
for i in 1..<line.len:
if line[i] == '%':
jsonFile = line[1 .. i - 1]
jsonPath = line[i + 1 .. ^1]
break
if isNil(jsonFile):
echo "Second % missing in line " & $lineNum & "! content:\n"
echo line
quit 1
let root = parseFile(jsonFile)
var prefix = ""
for i in countdown(jsonFile.len - 1, 0):
if jsonFile[i] == '/':
prefix = jsonFile[0..i]
break
outputExamples(root.gotoPath(jsonPath), prefix)
else:
append(line)