* better docs and tests * a bit better only clean trailing whitespace
This commit is contained in:
parent
1aaa67fc18
commit
48d7c40553
2 changed files with 141 additions and 18 deletions
|
|
@ -107,6 +107,70 @@
|
||||||
## var dict = loadConfig("config.ini")
|
## var dict = loadConfig("config.ini")
|
||||||
## dict.delSectionKey("Author","email")
|
## dict.delSectionKey("Author","email")
|
||||||
## dict.writeConfig("config.ini")
|
## dict.writeConfig("config.ini")
|
||||||
|
##
|
||||||
|
## Supported INI File structure
|
||||||
|
## ----------------------------
|
||||||
|
## The examples below are supported:
|
||||||
|
##
|
||||||
|
|
||||||
|
# taken from https://docs.python.org/3/library/configparser.html#supported-ini-file-structure
|
||||||
|
runnableExamples:
|
||||||
|
import streams
|
||||||
|
|
||||||
|
var dict = loadConfig(newStringStream("""[Simple Values]
|
||||||
|
key=value
|
||||||
|
spaces in keys=allowed
|
||||||
|
spaces in values=allowed as well
|
||||||
|
spaces around the delimiter = obviously
|
||||||
|
you can also use : to delimit keys from values
|
||||||
|
[All Values Are Strings]
|
||||||
|
values like this: 19990429
|
||||||
|
or this: 3.14159265359
|
||||||
|
are they treated as numbers : no
|
||||||
|
integers floats and booleans are held as: strings
|
||||||
|
can use the API to get converted values directly: true
|
||||||
|
[No Values]
|
||||||
|
key_without_value
|
||||||
|
# empty string value is not allowed =
|
||||||
|
[ Seletion A ]
|
||||||
|
space around section name will be ignored
|
||||||
|
[You can use comments]
|
||||||
|
# like this
|
||||||
|
; or this
|
||||||
|
# By default only in an empty line.
|
||||||
|
# Inline comments can be harmful because they prevent users
|
||||||
|
# from using the delimiting characters as parts of values.
|
||||||
|
# That being said, this can be customized.
|
||||||
|
[Sections Can Be Indented]
|
||||||
|
can_values_be_as_well = True
|
||||||
|
does_that_mean_anything_special = False
|
||||||
|
purpose = formatting for readability
|
||||||
|
# Did I mention we can indent comments, too?
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
let section1 = "Simple Values"
|
||||||
|
doAssert dict.getSectionValue(section1, "key") == "value"
|
||||||
|
doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed"
|
||||||
|
doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well"
|
||||||
|
doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously"
|
||||||
|
doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values"
|
||||||
|
|
||||||
|
let section2 = "All Values Are Strings"
|
||||||
|
doAssert dict.getSectionValue(section2, "values like this") == "19990429"
|
||||||
|
doAssert dict.getSectionValue(section2, "or this") == "3.14159265359"
|
||||||
|
doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no"
|
||||||
|
doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings"
|
||||||
|
doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true"
|
||||||
|
|
||||||
|
let section3 = "Seletion A"
|
||||||
|
doAssert dict.getSectionValue(section3,
|
||||||
|
"space around section name will be ignored", "not an empty value") == ""
|
||||||
|
|
||||||
|
let section4 = "Sections Can Be Indented"
|
||||||
|
doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True"
|
||||||
|
doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
|
||||||
|
doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability"
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, lexbase, streams, tables
|
strutils, lexbase, streams, tables
|
||||||
|
|
@ -151,7 +215,7 @@ type
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
const
|
const
|
||||||
SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', '/', '\\', '-'}
|
SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', ' ', '\x80'..'\xFF', '.', '/', '\\', '-'}
|
||||||
|
|
||||||
proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.}
|
proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.}
|
||||||
|
|
||||||
|
|
@ -306,6 +370,10 @@ proc getSymbol(c: var CfgParser, tok: var Token) =
|
||||||
add(tok.literal, c.buf[pos])
|
add(tok.literal, c.buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
if not (c.buf[pos] in SymChars): break
|
if not (c.buf[pos] in SymChars): break
|
||||||
|
|
||||||
|
while tok.literal.len > 0 and tok.literal[^1] == ' ':
|
||||||
|
tok.literal.setLen(tok.literal.len - 1)
|
||||||
|
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
tok.kind = tkSymbol
|
tok.kind = tkSymbol
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,27 @@ discard """
|
||||||
import parsecfg, streams
|
import parsecfg, streams
|
||||||
|
|
||||||
when not defined(js):
|
when not defined(js):
|
||||||
# bug #6046
|
|
||||||
var config = newConfig()
|
|
||||||
config.setSectionKey("foo", "bar", "-1")
|
|
||||||
config.setSectionKey("foo", "foo", "abc")
|
|
||||||
|
|
||||||
from stdtest/specialpaths import buildDir
|
from stdtest/specialpaths import buildDir
|
||||||
import os
|
import os
|
||||||
|
# bug #6046
|
||||||
|
block:
|
||||||
|
var config = newConfig()
|
||||||
|
config.setSectionKey("foo", "bar", "-1")
|
||||||
|
config.setSectionKey("foo", "foo", "abc")
|
||||||
|
|
||||||
const file = buildDir / "tparsecfg.ini"
|
const file = buildDir / "tparsecfg.ini"
|
||||||
config.writeConfig(file)
|
config.writeConfig(file)
|
||||||
|
|
||||||
# file now contains
|
# file now contains
|
||||||
# [foo]
|
# [foo]
|
||||||
# bar=-1
|
# bar=-1
|
||||||
# foo=abc
|
# foo=abc
|
||||||
|
|
||||||
var config2 = loadConfig(file)
|
|
||||||
let bar = config2.getSectionValue("foo", "bar")
|
|
||||||
let foo = config2.getSectionValue("foo", "foo")
|
|
||||||
assert(bar == "-1")
|
|
||||||
assert(foo == "abc")
|
|
||||||
|
|
||||||
|
var config2 = loadConfig(file)
|
||||||
|
let bar = config2.getSectionValue("foo", "bar")
|
||||||
|
let foo = config2.getSectionValue("foo", "foo")
|
||||||
|
assert(bar == "-1")
|
||||||
|
assert(foo == "abc")
|
||||||
|
|
||||||
## Creating a configuration file.
|
## Creating a configuration file.
|
||||||
var dict1 = newConfig()
|
var dict1 = newConfig()
|
||||||
|
|
@ -78,3 +77,59 @@ name=hello
|
||||||
name=lihf8515
|
name=lihf8515
|
||||||
qq=10214028
|
qq=10214028
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
block:
|
||||||
|
var dict = loadConfig(newStringStream("""[Simple Values]
|
||||||
|
key=value
|
||||||
|
spaces in keys=allowed
|
||||||
|
spaces in values=allowed as well
|
||||||
|
spaces around the delimiter = obviously
|
||||||
|
you can also use : to delimit keys from values
|
||||||
|
[All Values Are Strings]
|
||||||
|
values like this: 19990429
|
||||||
|
or this: 3.14159265359
|
||||||
|
are they treated as numbers : no
|
||||||
|
integers floats and booleans are held as: strings
|
||||||
|
can use the API to get converted values directly: true
|
||||||
|
[No Values]
|
||||||
|
key_without_value
|
||||||
|
# empty string value is not allowed =
|
||||||
|
[ Seletion A ]
|
||||||
|
space around section name will be ignored
|
||||||
|
[You can use comments]
|
||||||
|
# like this
|
||||||
|
; or this
|
||||||
|
# By default only in an empty line.
|
||||||
|
# Inline comments can be harmful because they prevent users
|
||||||
|
# from using the delimiting characters as parts of values.
|
||||||
|
# That being said, this can be customized.
|
||||||
|
[Sections Can Be Indented]
|
||||||
|
can_values_be_as_well = True
|
||||||
|
does_that_mean_anything_special = False
|
||||||
|
purpose = formatting for readability
|
||||||
|
# Did I mention we can indent comments, too?
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
let section1 = "Simple Values"
|
||||||
|
doAssert dict.getSectionValue(section1, "key") == "value"
|
||||||
|
doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed"
|
||||||
|
doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well"
|
||||||
|
doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously"
|
||||||
|
doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values"
|
||||||
|
|
||||||
|
let section2 = "All Values Are Strings"
|
||||||
|
doAssert dict.getSectionValue(section2, "values like this") == "19990429"
|
||||||
|
doAssert dict.getSectionValue(section2, "or this") == "3.14159265359"
|
||||||
|
doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no"
|
||||||
|
doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings"
|
||||||
|
doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true"
|
||||||
|
|
||||||
|
let section3 = "Seletion A"
|
||||||
|
doAssert dict.getSectionValue(section3,
|
||||||
|
"space around section name will be ignored", "not an empty value") == ""
|
||||||
|
|
||||||
|
let section4 = "Sections Can Be Indented"
|
||||||
|
doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True"
|
||||||
|
doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
|
||||||
|
doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue