Presenter: Let user decide about newline style

* Added PresentationOptions object; merged PresentationStyle,
   indentationStep and NewLineStyle in it
 * Updated signatures of relevant procs
 * Implemented user-defined newline style in presenter
This commit is contained in:
Felix Krause 2016-02-26 21:55:59 +01:00
parent 349cb19912
commit 46913867e2
5 changed files with 154 additions and 112 deletions

View File

@ -189,16 +189,16 @@ proc serialize*(doc: YamlDocument, tagLib: TagLibrary, a: AnchorStyle = asTidy):
result = initYamlStream(backend) result = initYamlStream(backend)
proc dumpDOM*(doc: YamlDocument, target: Stream, proc dumpDOM*(doc: YamlDocument, target: Stream,
style: PresentationStyle = psDefault, anchorStyle: AnchorStyle = asTidy,
anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2) options: PresentationOptions = defaultPresentationOptions)
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError].} = {.raises: [YamlPresenterJsonError, YamlPresenterOutputError].} =
## Dump a YamlDocument as YAML character stream. ## Dump a YamlDocument as YAML character stream.
var var
tagLib = initExtendedTagLibrary() tagLib = initExtendedTagLibrary()
events = serialize(doc, tagLib, events = serialize(doc, tagLib,
if style == psJson: asNone else: anchorStyle) if options.style == psJson: asNone else: anchorStyle)
try: try:
present(events, target, tagLib, style, indentationStep) present(events, target, tagLib, options)
except YamlStreamError: except YamlStreamError:
# serializing object does not raise any errors, so we can ignore this # serializing object does not raise any errors, so we can ignore this
assert false, "Can never happen" assert false, "Can never happen"

View File

@ -16,6 +16,12 @@ type
ScalarStyle = enum ScalarStyle = enum
sLiteral, sFolded, sPlain, sDoubleQuoted sLiteral, sFolded, sPlain, sDoubleQuoted
proc defineOptions*(style: PresentationStyle = psDefault,
indentationStep: int = 2, newlines:
NewLineStyle = nlOSDefault): PresentationOptions =
result = PresentationOptions(style: style, indentationStep: indentationStep,
newlines: newlines)
proc inspect(scalar: string, indentation: int, proc inspect(scalar: string, indentation: int,
words, lines: var seq[tuple[start, finish: int]]): words, lines: var seq[tuple[start, finish: int]]):
ScalarStyle {.raises: [].} = ScalarStyle {.raises: [].} =
@ -89,7 +95,8 @@ proc inspect(scalar: string, indentation: int,
elif canUsePlain: result = sPlain elif canUsePlain: result = sPlain
else: result = sDoubleQuoted else: result = sDoubleQuoted
proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int) proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int,
newline: string)
{.raises: [YamlPresenterOutputError].} = {.raises: [YamlPresenterOutputError].} =
var curPos = indentation var curPos = indentation
try: try:
@ -97,7 +104,8 @@ proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int)
curPos.inc() curPos.inc()
for c in scalar: for c in scalar:
if curPos == 79: if curPos == 79:
s.write("\\\l") s.write('\\')
s.write(newline)
s.write(repeat(' ', indentation)) s.write(repeat(' ', indentation))
curPos = indentation curPos = indentation
if c == ' ': if c == ' ':
@ -155,14 +163,14 @@ proc writeDoubleQuotedJson(scalar: string, s: Stream)
raise e raise e
proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream, proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream,
lines: seq[tuple[start, finish: int]]) lines: seq[tuple[start, finish: int]], newline: string)
{.raises: [YamlPresenterOutputError].} = {.raises: [YamlPresenterOutputError].} =
try: try:
s.write('|') s.write('|')
if scalar[^1] != '\l': s.write('-') if scalar[^1] != '\l': s.write('-')
if scalar[0] in [' ', '\t']: s.write($indentStep) if scalar[0] in [' ', '\t']: s.write($indentStep)
for line in lines: for line in lines:
s.write('\l') s.write(newline)
s.write(repeat(' ', indentation + indentStep)) s.write(repeat(' ', indentation + indentStep))
if line.finish >= line.start: if line.finish >= line.start:
s.write(scalar[line.start .. line.finish]) s.write(scalar[line.start .. line.finish])
@ -173,18 +181,18 @@ proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream,
raise e raise e
proc writeFolded(scalar: string, indentation, indentStep: int, s: Stream, proc writeFolded(scalar: string, indentation, indentStep: int, s: Stream,
words: seq[tuple[start, finish: int]]) words: seq[tuple[start, finish: int]], newline: string)
{.raises: [YamlPresenterOutputError].} = {.raises: [YamlPresenterOutputError].} =
try: try:
s.write("|-") s.write("|-")
var curPos = 80 var curPos = 80
for word in words: for word in words:
if word.start > 0 and scalar[word.start - 1] == '\l': if word.start > 0 and scalar[word.start - 1] == '\l':
s.write("\l\l") s.write(newline & newline)
s.write(repeat(' ', indentation + indentStep)) s.write(repeat(' ', indentation + indentStep))
curPos = indentation + indentStep curPos = indentation + indentStep
elif curPos + (word.finish - word.start) > 80: elif curPos + (word.finish - word.start) > 80:
s.write('\l') s.write(newline)
s.write(repeat(' ', indentation + indentStep)) s.write(repeat(' ', indentation + indentStep))
curPos = indentation + indentStep curPos = indentation + indentStep
else: else:
@ -207,12 +215,12 @@ template safeWrite(s: string or char) {.dirty.} =
raise e raise e
proc startItem(target: Stream, style: PresentationStyle, indentation: int, proc startItem(target: Stream, style: PresentationStyle, indentation: int,
state: var DumperState, isObject: bool) state: var DumperState, isObject: bool, newline: string)
{.raises: [YamlPresenterOutputError].} = {.raises: [YamlPresenterOutputError].} =
try: try:
case state case state
of dBlockMapValue: of dBlockMapValue:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
if isObject or style == psCanonical: if isObject or style == psCanonical:
target.write("? ") target.write("? ")
@ -222,7 +230,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
of dBlockInlineMap: of dBlockInlineMap:
state = dBlockImplicitMapKey state = dBlockImplicitMapKey
of dBlockExplicitMapKey: of dBlockExplicitMapKey:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
target.write(": ") target.write(": ")
state = dBlockMapValue state = dBlockMapValue
@ -231,14 +239,14 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
state = dBlockMapValue state = dBlockMapValue
of dFlowExplicitMapKey: of dFlowExplicitMapKey:
if style != psMinimal: if style != psMinimal:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
target.write(": ") target.write(": ")
state = dFlowMapValue state = dFlowMapValue
of dFlowMapValue: of dFlowMapValue:
if (isObject and style != psMinimal) or if (isObject and style != psMinimal) or
style in [psJson, psCanonical]: style in [psJson, psCanonical]:
target.write(",\l" & repeat(' ', indentation)) target.write(',' & newline & repeat(' ', indentation))
if style == psJson: if style == psJson:
state = dFlowImplicitMapKey state = dFlowImplicitMapKey
else: else:
@ -253,7 +261,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
of dFlowMapStart: of dFlowMapStart:
if (isObject and style != psMinimal) or if (isObject and style != psMinimal) or
style in [psJson, psCanonical]: style in [psJson, psCanonical]:
target.write("\l" & repeat(' ', indentation)) target.write(newline & repeat(' ', indentation))
if style == psJson: if style == psJson:
state = dFlowImplicitMapKey state = dFlowImplicitMapKey
else: else:
@ -265,7 +273,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
target.write(": ") target.write(": ")
state = dFlowMapValue state = dFlowMapValue
of dBlockSequenceItem: of dBlockSequenceItem:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
target.write("- ") target.write("- ")
of dFlowSequenceStart: of dFlowSequenceStart:
@ -273,7 +281,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
of psMinimal, psDefault: of psMinimal, psDefault:
discard discard
of psCanonical, psJson: of psCanonical, psJson:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
of psBlockOnly: of psBlockOnly:
discard # can never happen discard # can never happen
@ -283,7 +291,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
of psMinimal, psDefault: of psMinimal, psDefault:
target.write(", ") target.write(", ")
of psCanonical, psJson: of psCanonical, psJson:
target.write(",\l") target.write(',' & newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
of psBlockOnly: of psBlockOnly:
discard # can never happen discard # can never happen
@ -327,24 +335,24 @@ proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: TagLibrary,
raise e raise e
proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
style: PresentationStyle = psDefault, options: PresentationOptions = defaultPresentationOptions) =
indentationStep: int = 2) =
var var
indentation = 0 indentation = 0
levels = newSeq[DumperState]() levels = newSeq[DumperState]()
cached = initQueue[YamlStreamEvent]() cached = initQueue[YamlStreamEvent]()
let newline = if options.newlines == nlLF: "\l"
elif options.newlines == nlCRLF: "\c\l" else: "\n"
while cached.len > 0 or not s.finished(): while cached.len > 0 or not s.finished():
let item = if cached.len > 0: cached.dequeue else: s.next() let item = if cached.len > 0: cached.dequeue else: s.next()
case item.kind case item.kind
of yamlStartDocument: of yamlStartDocument:
if style != psJson: if options.style != psJson:
# TODO: tag directives # TODO: tag directives
try: try:
target.write("%YAML 1.2\l") target.write("%YAML 1.2" & newline)
if tagLib.secondaryPrefix != yamlTagRepositoryPrefix: if tagLib.secondaryPrefix != yamlTagRepositoryPrefix:
target.write("%TAG !! " & target.write("%TAG !! " &
tagLib.secondaryPrefix & '\l') tagLib.secondaryPrefix & newline)
target.write("--- ") target.write("--- ")
except: except:
var e = newException(YamlPresenterOutputError, "") var e = newException(YamlPresenterOutputError, "")
@ -352,16 +360,16 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
raise e raise e
of yamlScalar: of yamlScalar:
if levels.len == 0: if levels.len == 0:
if style != psJson: if options.style != psJson:
safeWrite('\l') safeWrite(newline)
else: else:
startItem(target, style, indentation, levels[levels.high], startItem(target, options.style, indentation,
false) levels[levels.high], false, newline)
if style != psJson: if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.scalarTag, tagLib, item.scalarAnchor) item.scalarTag, tagLib, item.scalarAnchor)
if style == psJson: if options.style == psJson:
let hint = guessType(item.scalarContent) let hint = guessType(item.scalarContent)
if item.scalarTag in [yTagQuestionMark, yTagBoolean] and if item.scalarTag in [yTagQuestionMark, yTagBoolean] and
hint in [yTypeBoolTrue, yTypeBoolFalse]: hint in [yTypeBoolTrue, yTypeBoolFalse]:
@ -384,26 +392,28 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
safeWrite(item.scalarContent) safeWrite(item.scalarContent)
else: else:
writeDoubleQuotedJson(item.scalarContent, target) writeDoubleQuotedJson(item.scalarContent, target)
elif style == psCanonical: elif options.style == psCanonical:
writeDoubleQuoted(item.scalarContent, target, writeDoubleQuoted(item.scalarContent, target,
indentation + indentationStep) indentation + options.indentationStep,
newline)
else: else:
var words, lines = newSeq[tuple[start, finish: int]]() var words, lines = newSeq[tuple[start, finish: int]]()
case item.scalarContent.inspect(indentation + indentationStep, case item.scalarContent.inspect(
words, lines) indentation + options.indentationStep, words, lines)
of sLiteral: writeLiteral(item.scalarContent, indentation, of sLiteral: writeLiteral(item.scalarContent, indentation,
indentationStep, target, lines) options.indentationStep, target, lines, newline)
of sFolded: writeFolded(item.scalarContent, indentation, of sFolded: writeFolded(item.scalarContent, indentation,
indentationStep, target, words) options.indentationStep, target, words, newline)
of sPlain: safeWrite(item.scalarContent) of sPlain: safeWrite(item.scalarContent)
of sDoubleQuoted: writeDoubleQuoted(item.scalarContent, target, of sDoubleQuoted: writeDoubleQuoted(item.scalarContent, target,
indentation + indentationStep) indentation + options.indentationStep, newline)
of yamlAlias: of yamlAlias:
if style == psJson: if options.style == psJson:
raise newException(YamlPresenterJsonError, raise newException(YamlPresenterJsonError,
"Alias not allowed in JSON output") "Alias not allowed in JSON output")
assert levels.len > 0 assert levels.len > 0
startItem(target, style, indentation, levels[levels.high], false) startItem(target, options.style, indentation, levels[levels.high],
false, newline)
try: try:
target.write('*') target.write('*')
target.write(cast[byte]('a') + cast[byte](item.aliasTarget)) target.write(cast[byte]('a') + cast[byte](item.aliasTarget))
@ -413,7 +423,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
raise e raise e
of yamlStartSequence: of yamlStartSequence:
var nextState: DumperState var nextState: DumperState
case style case options.style
of psDefault: of psDefault:
var length = 0 var length = 0
while true: while true:
@ -445,33 +455,34 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
if levels.len == 0: if levels.len == 0:
if nextState == dBlockSequenceItem: if nextState == dBlockSequenceItem:
if style != psJson: if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.seqTag, tagLib, item.seqAnchor) item.seqTag, tagLib, item.seqAnchor)
else: else:
if style != psJson: if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.seqTag, tagLib, item.seqAnchor) item.seqTag, tagLib, item.seqAnchor)
safeWrite('\l') safeWrite(newline)
indentation += indentationStep indentation += options.indentationStep
else: else:
startItem(target, style, indentation, levels[levels.high], true) startItem(target, options.style, indentation,
if style != psJson: levels[levels.high], true, newline)
if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.seqTag, tagLib, item.seqAnchor) item.seqTag, tagLib, item.seqAnchor)
indentation += indentationStep indentation += options.indentationStep
if nextState == dFlowSequenceStart: if nextState == dFlowSequenceStart:
safeWrite('[') safeWrite('[')
if levels.len > 0 and style in [psJson, psCanonical] and if levels.len > 0 and options.style in [psJson, psCanonical] and
levels[levels.high] in levels[levels.high] in
[dBlockExplicitMapKey, dBlockMapValue, [dBlockExplicitMapKey, dBlockMapValue,
dBlockImplicitMapKey, dBlockSequenceItem]: dBlockImplicitMapKey, dBlockSequenceItem]:
indentation += indentationStep indentation += options.indentationStep
levels.add(nextState) levels.add(nextState)
of yamlStartMap: of yamlStartMap:
var nextState: DumperState var nextState: DumperState
case style case options.style
of psDefault: of psDefault:
type MapParseState = enum type MapParseState = enum
mpInitial, mpKey, mpValue, mpNeedBlock mpInitial, mpKey, mpValue, mpNeedBlock
@ -503,50 +514,50 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
nextState = dBlockMapValue nextState = dBlockMapValue
if levels.len == 0: if levels.len == 0:
if nextState == dBlockMapValue: if nextState == dBlockMapValue:
if style != psJson: if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.mapTag, tagLib, item.mapAnchor) item.mapTag, tagLib, item.mapAnchor)
else: else:
if style != psJson: if options.style != psJson:
safeWrite('\l') safeWrite(newline)
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.mapTag, tagLib, item.mapAnchor) item.mapTag, tagLib, item.mapAnchor)
indentation += indentationStep indentation += options.indentationStep
else: else:
if nextState in [dBlockMapValue, dBlockImplicitMapKey]: if nextState in [dBlockMapValue, dBlockImplicitMapKey]:
startItem(target, style, indentation, levels[levels.high], startItem(target, options.style, indentation,
true) levels[levels.high], true, newline)
if style != psJson: if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.mapTag, tagLib, item.mapAnchor) item.mapTag, tagLib, item.mapAnchor)
else: else:
startItem(target, style, indentation, levels[levels.high], startItem(target, options.style, indentation,
true) levels[levels.high], true, newline)
if style != psJson: if options.style != psJson:
writeTagAndAnchor(target, writeTagAndAnchor(target,
item.mapTag, tagLib, item.mapAnchor) item.mapTag, tagLib, item.mapAnchor)
indentation += indentationStep indentation += options.indentationStep
if nextState == dFlowMapStart: if nextState == dFlowMapStart:
safeWrite('{') safeWrite('{')
if levels.len > 0 and style in [psJson, psCanonical] and if levels.len > 0 and options.style in [psJson, psCanonical] and
levels[levels.high] in levels[levels.high] in
[dBlockExplicitMapKey, dBlockMapValue, [dBlockExplicitMapKey, dBlockMapValue,
dBlockImplicitMapKey, dBlockSequenceItem]: dBlockImplicitMapKey, dBlockSequenceItem]:
indentation += indentationStep indentation += options.indentationStep
levels.add(nextState) levels.add(nextState)
of yamlEndSequence: of yamlEndSequence:
assert levels.len > 0 assert levels.len > 0
case levels.pop() case levels.pop()
of dFlowSequenceItem: of dFlowSequenceItem:
case style case options.style
of psDefault, psMinimal, psBlockOnly: of psDefault, psMinimal, psBlockOnly:
safeWrite(']') safeWrite(']')
of psJson, psCanonical: of psJson, psCanonical:
indentation -= indentationStep indentation -= options.indentationStep
try: try:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
target.write(']') target.write(']')
except: except:
@ -558,29 +569,29 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
dBlockImplicitMapKey, dBlockSequenceItem]: dBlockImplicitMapKey, dBlockSequenceItem]:
continue continue
of dFlowSequenceStart: of dFlowSequenceStart:
if levels.len > 0 and style in [psJson, psCanonical] and if levels.len > 0 and options.style in [psJson, psCanonical] and
levels[levels.high] in levels[levels.high] in
[dBlockExplicitMapKey, dBlockMapValue, [dBlockExplicitMapKey, dBlockMapValue,
dBlockImplicitMapKey, dBlockSequenceItem]: dBlockImplicitMapKey, dBlockSequenceItem]:
indentation -= indentationStep indentation -= options.indentationStep
safeWrite(']') safeWrite(']')
of dBlockSequenceItem: of dBlockSequenceItem:
discard discard
else: else:
assert false assert false
indentation -= indentationStep indentation -= options.indentationStep
of yamlEndMap: of yamlEndMap:
assert levels.len > 0 assert levels.len > 0
let level = levels.pop() let level = levels.pop()
case level case level
of dFlowMapValue: of dFlowMapValue:
case style case options.style
of psDefault, psMinimal, psBlockOnly: of psDefault, psMinimal, psBlockOnly:
safeWrite('}') safeWrite('}')
of psJson, psCanonical: of psJson, psCanonical:
indentation -= indentationStep indentation -= options.indentationStep
try: try:
target.write('\l') target.write(newline)
target.write(repeat(' ', indentation)) target.write(repeat(' ', indentation))
target.write('}') target.write('}')
except: except:
@ -592,29 +603,29 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
dBlockImplicitMapKey, dBlockSequenceItem]: dBlockImplicitMapKey, dBlockSequenceItem]:
continue continue
of dFlowMapStart: of dFlowMapStart:
if levels.len > 0 and style in [psJson, psCanonical] and if levels.len > 0 and options.style in [psJson, psCanonical] and
levels[levels.high] in levels[levels.high] in
[dBlockExplicitMapKey, dBlockMapValue, [dBlockExplicitMapKey, dBlockMapValue,
dBlockImplicitMapKey, dBlockSequenceItem]: dBlockImplicitMapKey, dBlockSequenceItem]:
indentation -= indentationStep indentation -= options.indentationStep
safeWrite('}') safeWrite('}')
of dBlockMapValue, dBlockInlineMap: of dBlockMapValue, dBlockInlineMap:
discard discard
else: else:
assert false assert false
indentation -= indentationStep indentation -= options.indentationStep
of yamlEndDocument: of yamlEndDocument:
if finished(s): break if finished(s): break
safeWrite("...\l") safeWrite("..." & newline)
proc transform*(input: Stream, output: Stream, style: PresentationStyle, proc transform*(input: Stream, output: Stream,
indentationStep: int = 2) = options: PresentationOptions = defaultPresentationOptions) =
var var
taglib = initExtendedTagLibrary() taglib = initExtendedTagLibrary()
parser = newYamlParser(tagLib) parser = newYamlParser(tagLib)
events = parser.parse(input) events = parser.parse(input)
try: try:
if style == psCanonical: if options.style == psCanonical:
var specificTagEvents = iterator(): YamlStreamEvent = var specificTagEvents = iterator(): YamlStreamEvent =
for e in events: for e in events:
var event = e var event = e
@ -647,10 +658,9 @@ proc transform*(input: Stream, output: Stream, style: PresentationStyle,
event.scalarTag = yTagString event.scalarTag = yTagString
yield event yield event
var s = initYamlStream(specificTagEvents) var s = initYamlStream(specificTagEvents)
present(s, output, tagLib, style, present(s, output, tagLib, options)
indentationStep)
else: else:
present(events, output, tagLib, style, indentationStep) present(events, output, tagLib, options)
except YamlStreamError: except YamlStreamError:
var e = getCurrentException() var e = getCurrentException()
while e.parent of YamlStreamError: e = e.parent while e.parent of YamlStreamError: e = e.parent

View File

@ -635,13 +635,14 @@ proc represent*[T](value: T, ts: TagStyle = tsRootOnly,
else: else:
result = initYamlStream(objStream) result = initYamlStream(objStream)
proc dump*[K](value: K, target: Stream, style: PresentationStyle = psDefault, proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly,
tagStyle: TagStyle = tsRootOnly, anchorStyle: AnchorStyle = asTidy,
anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2) = options: PresentationOptions = defaultPresentationOptions) =
var events = represent(value, if style == psCanonical: tsAll else: tagStyle, var events = represent(value,
if style == psJson: asNone else: anchorStyle) if options.style == psCanonical: tsAll else: tagStyle,
if options.style == psJson: asNone else: anchorStyle)
try: try:
present(events, target, serializationTagLibrary, style, indentationStep) present(events, target, serializationTagLibrary, options)
except YamlStreamError: except YamlStreamError:
# serializing object does not raise any errors, so we can ignore this # serializing object does not raise any errors, so we can ignore this
assert false, "Can never happen" assert false, "Can never happen"

View File

@ -55,6 +55,11 @@ proc newNode(v: string): ref Node =
result.next = nil result.next = nil
suite "Serialization": suite "Serialization":
setup:
let
blockOnly = defineOptions(style=psBlockOnly)
test "Serialization: Load string sequence": test "Serialization: Load string sequence":
let input = newStringStream(" - a\n - b") let input = newStringStream(" - a\n - b")
var result: seq[string] var result: seq[string]
@ -66,7 +71,7 @@ suite "Serialization":
test "Serialization: Represent string sequence": test "Serialization: Represent string sequence":
var input = @["a", "b"] var input = @["a", "b"]
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsNone) dump(input, output, tsNone, asTidy, blockOnly)
assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data
test "Serialization: Load Table[int, string]": test "Serialization: Load Table[int, string]":
@ -82,7 +87,7 @@ suite "Serialization":
input[23] = "dreiundzwanzig" input[23] = "dreiundzwanzig"
input[42] = "zweiundvierzig" input[42] = "zweiundvierzig"
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsNone) dump(input, output, tsNone, asTidy, blockOnly)
assertStringEqual( assertStringEqual(
"%YAML 1.2\n--- \n23: dreiundzwanzig\n42: zweiundvierzig", "%YAML 1.2\n--- \n23: dreiundzwanzig\n42: zweiundvierzig",
output.data) output.data)
@ -100,7 +105,7 @@ suite "Serialization":
let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32],
@[6.int32]] @[6.int32]]
var output = newStringStream() var output = newStringStream()
dump(input, output, psDefault, tsNone) dump(input, output, tsNone)
assertStringEqual "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]", assertStringEqual "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]",
output.data output.data
@ -116,7 +121,7 @@ suite "Serialization":
test "Serialization: Represent Enum": test "Serialization: Represent Enum":
let input = @[tlRed, tlGreen, tlYellow] let input = @[tlRed, tlGreen, tlYellow]
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsNone) dump(input, output, tsNone, asTidy, blockOnly)
assertStringEqual "%YAML 1.2\n--- \n- tlRed\n- tlGreen\n- tlYellow", assertStringEqual "%YAML 1.2\n--- \n- tlRed\n- tlGreen\n- tlYellow",
output.data output.data
@ -131,7 +136,7 @@ suite "Serialization":
test "Serialization: Represent Tuple": test "Serialization: Represent Tuple":
let input = (str: "value", i: 42.int32, b: true) let input = (str: "value", i: 42.int32, b: true)
var output = newStringStream() var output = newStringStream()
dump(input, output, psDefault, tsNone) dump(input, output, tsNone)
assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y", assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y",
output.data output.data
@ -146,7 +151,7 @@ suite "Serialization":
test "Serialization: Represent custom object": test "Serialization: Represent custom object":
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12) let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsNone) dump(input, output, tsNone, asTidy, blockOnly)
assertStringEqual( assertStringEqual(
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12", "%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12",
output.data) output.data)
@ -162,7 +167,7 @@ suite "Serialization":
test "Serialization: Represent sequence with explicit tags": test "Serialization: Represent sequence with explicit tags":
let input = @["one", "two"] let input = @["one", "two"]
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsAll) dump(input, output, tsAll, asTidy, blockOnly)
assertStringEqual("%YAML 1.2\n--- !nim:system:seq(" & assertStringEqual("%YAML 1.2\n--- !nim:system:seq(" &
"tag:yaml.org,2002:str) \n- !!str one\n- !!str two", "tag:yaml.org,2002:str) \n- !!str one\n- !!str two",
output.data) output.data)
@ -179,7 +184,7 @@ suite "Serialization":
test "Serialization: Represent custom object with explicit root tag": test "Serialization: Represent custom object with explicit root tag":
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12) let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsRootOnly) dump(input, output, tsRootOnly, asTidy, blockOnly)
assertStringEqual("%YAML 1.2\n" & assertStringEqual("%YAML 1.2\n" &
"--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12", "--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12",
output.data) output.data)
@ -193,7 +198,7 @@ suite "Serialization":
b.next = c b.next = c
c.next = a c.next = a
var output = newStringStream() var output = newStringStream()
dump(a, output, psBlockOnly, tsRootOnly) dump(a, output, tsRootOnly, asTidy, blockOnly)
assertStringEqual """%YAML 1.2 assertStringEqual """%YAML 1.2
--- !example.net:Node &a --- !example.net:Node &a
value: a value: a
@ -252,7 +257,7 @@ next:
input.add(new string) input.add(new string)
input[1][] = "~" input[1][] = "~"
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsRootOnly) dump(input, output, tsRootOnly, asTidy, blockOnly)
assertStringEqual "%YAML 1.2\n--- !nim:system:seq(tag:yaml.org,2002:str) \n- !!null ~\n- !!str ~", assertStringEqual "%YAML 1.2\n--- !nim:system:seq(tag:yaml.org,2002:str) \n- !!null ~\n- !!str ~",
output.data output.data
@ -267,7 +272,7 @@ next:
test "Serialization: Custom representObject": test "Serialization: Custom representObject":
let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt] let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt]
var output = newStringStream() var output = newStringStream()
dump(input, output, psBlockOnly, tsAll) dump(input, output, tsAll, asTidy, blockOnly)
assertStringEqual """%YAML 1.2 assertStringEqual """%YAML 1.2
--- !nim:system:seq(test:BetterInt) --- !nim:system:seq(test:BetterInt)
- !test:BetterInt 1 - !test:BetterInt 1

View File

@ -205,6 +205,22 @@ type
## object is referenced again afterwards ## object is referenced again afterwards
asNone, asTidy, asAlways asNone, asTidy, asAlways
NewLineStyle* = enum
## What kind of newline sequence is used when presenting.
##
## - ``nlLF``: Use a single linefeed char as newline.
## - ``nlCRLF``: Use a sequence of carriage return and linefeed as
## newline.
## - ``nlOSDefault``: Use the target operation system's default newline
## sequence (CRLF on Windows, LF everywhere else).
nlLF, nlCRLF, nlOSDefault
PresentationOptions* = object
## Options for generating a YAML character stream
style*: PresentationStyle
indentationStep*: int
newlines*: NewLineStyle
RefNodeData = object RefNodeData = object
p: pointer p: pointer
count: int count: int
@ -361,6 +377,10 @@ const
yamlTagRepositoryPrefix* = "tag:yaml.org,2002:" yamlTagRepositoryPrefix* = "tag:yaml.org,2002:"
defaultPresentationOptions* =
PresentationOptions(style: psDefault, indentationStep: 2,
newlines: nlOSDefault)
# interface # interface
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].} proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].}
@ -495,6 +515,13 @@ proc getLineContent*(p: YamlParser, marker: bool = true): string {.raises: [].}
proc parse*(p: YamlParser, s: Stream): YamlStream {.raises: [].} proc parse*(p: YamlParser, s: Stream): YamlStream {.raises: [].}
## Parse the given stream as YAML character stream. ## Parse the given stream as YAML character stream.
proc defineOptions*(style: PresentationStyle = psDefault,
indentationStep: int = 2, newlines:
NewLineStyle = nlOSDefault): PresentationOptions
{.raises: [].}
## Define a set of options for presentation. Convenience proc that requires
## you to only set those values that should not equal the default.
proc constructJson*(s: var YamlStream): seq[JsonNode] proc constructJson*(s: var YamlStream): seq[JsonNode]
{.raises: [YamlConstructionError, YamlStreamError].} {.raises: [YamlConstructionError, YamlStreamError].}
## Construct an in-memory JSON tree from a YAML event stream. The stream may ## Construct an in-memory JSON tree from a YAML event stream. The stream may
@ -516,15 +543,14 @@ proc loadToJson*(s: Stream): seq[JsonNode] {.raises: [].}
## from a YAML character stream. ## from a YAML character stream.
proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
style: PresentationStyle = psDefault, options: PresentationOptions = defaultPresentationOptions)
indentationStep: int = 2) {.raises: [YamlPresenterJsonError, {.raises: [YamlPresenterJsonError, YamlPresenterOutputError,
YamlPresenterOutputError,
YamlStreamError].} YamlStreamError].}
## Convert ``s`` to a YAML character stream and write it to ``target``. ## Convert ``s`` to a YAML character stream and write it to ``target``.
proc transform*(input: Stream, output: Stream, style: PresentationStyle, proc transform*(input: Stream, output: Stream,
indentationStep: int = 2) {.raises: [IOError, YamlParserError, options: PresentationOptions = defaultPresentationOptions)
YamlPresenterJsonError, {.raises: [IOError, YamlParserError, YamlPresenterJsonError,
YamlPresenterOutputError].} YamlPresenterOutputError].}
## Parser ``input`` as YAML character stream and then dump it to ``output`` ## Parser ``input`` as YAML character stream and then dump it to ``output``
## while resolving non-specific tags to the ones in the YAML core tag ## while resolving non-specific tags to the ones in the YAML core tag
@ -564,9 +590,9 @@ proc represent*[T](value: T, ts: TagStyle = tsRootOnly,
a: AnchorStyle = asTidy): YamlStream {.raises: [].} a: AnchorStyle = asTidy): YamlStream {.raises: [].}
## Represents a Nim value as ``YamlStream`` ## Represents a Nim value as ``YamlStream``
proc dump*[K](value: K, target: Stream, style: PresentationStyle = psDefault, proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly,
tagStyle: TagStyle = tsRootOnly, anchorStyle: AnchorStyle = asTidy,
anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2) options: PresentationOptions = defaultPresentationOptions)
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError].} {.raises: [YamlPresenterJsonError, YamlPresenterOutputError].}
## Dump a Nim value as YAML character stream. ## Dump a Nim value as YAML character stream.