mirror of https://github.com/status-im/NimYAML.git
Documented custom serialization.
* Also improved style of testing ground
This commit is contained in:
parent
151d795f07
commit
d62aac16bc
|
@ -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)
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue