Documented custom serialization.

* Also improved style of testing ground
This commit is contained in:
Felix Krause 2016-02-16 20:08:44 +01:00
parent 151d795f07
commit d62aac16bc
3 changed files with 144 additions and 53 deletions

View File

@ -158,9 +158,54 @@ constructObject
result: var MyObject) result: var MyObject)
{.raises: [YamlConstructionError, YamlStreamError.} {.raises: [YamlConstructionError, YamlStreamError.}
This proc should construct the type from a ``YamlStream``. This proc should construct the type from a ``YamlStream``. Follow the following
guidelines when implementing a custom ``constructObject`` proc:
**TBD: More documentation here** - For constructing a value from a YAML scalar, consider using the
``constructScalarItem`` template, which will automatically catch exceptions
and wrap them with a ``YamlConstructionError``, and also will assure that the
item you use for construction is a ``yamlScalar``. See below for an example.
- For constructing a value from a YAML sequence or map, you **must** use the
``constructChild`` proc for child values if you want to use their
``constructObject`` implementation. This will check their tag and anchor.
Always try to construct child values that way.
- For non-scalars, make sure that the last value you remove from the stream is
the object's ending event (``yamlEndMap`` or ``yamlEndSequence``)
- Use `peek <yaml.html#peek,YamlStream>`_ for inspecting the next event in
the ``YamlStream`` without removing it.
- Never write a ``constructObject`` proc for a ``ref`` type. ``ref`` types are
always handled by NimYAML itself. You can only customize the construction of
the underlying object.
The following example for constructing from a YAML scalar value is the actual
implementation of constructing ``int`` types:
.. code-block:: nim
proc constructObject*[T: int8|int16|int32|int64](
s: var YamlStream, c: ConstructionContext, result: var T)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, name(T)):
result = T(parseBiggestInt(item.scalarContent))
The following example for constructiong from a YAML non-scalar is the actual
implementation of constructing ``seq`` types:
.. code-block:: nim
proc constructObject*[T](s: var YamlStream, c: ConstructionContext,
result: var seq[T])
{.raises: [YamlConstructionError, YamlStreamError].} =
let event = s.next()
if event.kind != yamlStartSequence:
raise newException(YamlConstructionError, "Expected sequence start")
result = newSeq[T]()
while s.peek().kind != yamlEndSequence:
var item: T
constructChild(s, c, item)
result.add(item)
discard s.next()
representObject representObject
--------------- ---------------
@ -171,6 +216,47 @@ representObject
c: SerializationContext): RawYamlStream {.raises: [].} c: SerializationContext): RawYamlStream {.raises: [].}
This proc should return an iterator over ``YamlStreamEvent`` which represents This proc should return an iterator over ``YamlStreamEvent`` which represents
the type. the type. Follow the following guidelines when implementing a custom
``representObject`` proc:
**TBD: More documentation here** - You can use the helper template
`presentTag <yaml.html#presentTag,typedesc,TagStyle>`_ for outputting the
tag.
- Always output the first tag with a ``yAnchorNone``. Anchors will be set
automatically by ``ref`` type handling.
- When outputting non-scalar types, you should use the ``representObject``
implementation of the child types, if possible.
- Check if the given ``TagStyle`` equals ``tsRootOnly`` and if yes, change it
to ``tsNone`` for the child values.
- Never write a ``representObject`` proc for ``ref`` types.
The following example for representing to a YAML scalar is the actual
implementation of representing ``int`` types:
.. code-block:: nim
proc representObject*[T: uint8|uint16|uint32|uint64](
value: T, ts: TagStyle, c: SerializationContext):
RawYamlStream {.raises: [].} =
result = iterator(): YamlStreamEvent =
yield scalarEvent($value, presentTag(T, ts), yAnchorNone)
The following example for representing to a YAML non-scalar is the actual
implementation of representing ``seq`` types:
.. code-block:: nim
proc representObject*[T](value: seq[T], ts: TagStyle,
c: SerializationContext): RawYamlStream {.raises: [].} =
result = iterator(): YamlStreamEvent =
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
yield YamlStreamEvent(kind: yamlStartSequence,
seqTag: presentTag(seq[T], ts),
seqAnchor: yAnchorNone)
for item in value:
var events = representObject(item, childTagStyle, c)
while true:
let event = events()
if finished(events): break
yield event
yield YamlStreamEvent(kind: yamlEndSequence)

View File

@ -87,6 +87,11 @@ dt a:before {
#testingground pre { #testingground pre {
font-size: small; font-size: small;
} }
#testingground #style-options {
margin-top: 10px;
width: 100%;
text-align: center;
}
#testingground .style-option { #testingground .style-option {
display: inline-block; display: inline-block;
margin-right: 20px; margin-right: 20px;

View File

@ -25,18 +25,20 @@
<h1 class="title">Testing Ground</h1> <h1 class="title">Testing Ground</h1>
<p>Input is being processed on the fly by a friendly web service and <p>Input is being processed on the fly by a friendly web service and
Output is updated as you type.</p> Output is updated as you type.</p>
<section id="testingground"> </div>
<table style="width: 100%; table-layout: fixed"> </article>
<thead> <section id="testingground">
<tr> <table style="width: 100%; table-layout: fixed">
<th>Input</th> <thead>
<th>Output</th> <tr>
</tr> <th>Input</th>
</thead> <th>Output</th>
<tbody> </tr>
<tr> </thead>
<td style="width: 50%; height: 400px; vertical-align: top;"> <tbody>
<textarea id="yaml-input" style="width: 100%; height: 100%"> <tr>
<td style="width: 50%; height: 550px; vertical-align: top;">
<textarea id="yaml-input" style="width: 100%; height: 100%">
- test some - test some
- {YAML: here} - {YAML: here}
- foo: bar - foo: bar
@ -47,42 +49,40 @@
: !!bool yes : !!bool yes
? reference to anchor ? reference to anchor
: *a</textarea> : *a</textarea>
</td> </td>
<td style="width: 50%; vertical-align: top; height: 400px; padding-left: 10px"> <td style="width: 50%; vertical-align: top; height: 550px; padding-left: 10px">
<div style="width:100%; height:100%; overflow: scroll"> <div style="width:100%; height:100%; overflow: scroll">
<pre id="yaml-output" style="width: 100%"/> <pre id="yaml-output" style="width: 100%"/>
</div> </div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div id="style-options"> <div id="style-options">
<p>Output style:</p> <div class="style-option">Output style:</div>
<div class="style-option"> <div class="style-option">
<input type="radio" name="style" id="style-minimal" value="minimal"/> <input type="radio" name="style" id="style-minimal" value="minimal"/>
<label for="style-minimal">Minimal</label> <label for="style-minimal">Minimal</label>
</div> </div>
<div class="style-option"> <div class="style-option">
<input type="radio" name="style" id="style-default" value="default"/> <input type="radio" name="style" id="style-default" value="default"/>
<label for="style-default">Default</label> <label for="style-default">Default</label>
</div> </div>
<div class="style-option"> <div class="style-option">
<input type="radio" name="style" id="style-canonical" value="canonical" checked="checked"/> <input type="radio" name="style" id="style-canonical" value="canonical" checked="checked"/>
<label for="style-canonical">Canonical</label> <label for="style-canonical">Canonical</label>
</div> </div>
<div class="style-option"> <div class="style-option">
<input type="radio" name="style" id="style-block" value="block"/> <input type="radio" name="style" id="style-block" value="block"/>
<label for="style-block">Block Only</label> <label for="style-block">Block Only</label>
</div> </div>
<div class="style-option"> <div class="style-option">
<input type="radio" name="style" id="style-json" value="json"/> <input type="radio" name="style" id="style-json" value="json"/>
<label for="style-json">JSON</label> <label for="style-json">JSON</label>
</div> </div>
</div>
</section>
</div> </div>
</article> </section>
<script type="text/javascript"> <script type="text/javascript">
function setTextContent(element, text) { function setTextContent(element, text) {
while (element.firstChild!==null) { while (element.firstChild!==null) {
element.removeChild(element.firstChild); // remove all existing content element.removeChild(element.firstChild); // remove all existing content
@ -137,6 +137,6 @@
radios[i].onclick = parse; radios[i].onclick = parse;
} }
parse(); parse();
</script> </script>
</body> </body>
</html> </html>