Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,17 +374,17 @@ Where `T` is the config type, `opt` is the option name, and `msg`
is the value of the `obsolete` pragma (which may be empty).

If the logger requires initialization, it can be set through
the `loggerSetup` parameter, for example:
the `onLoaded` parameter, for example:

```nim
type MyConf = object
# options

proc myLogger(config: MyConf) {.gcsafe, raises: [ConfigurationError].} =
proc myLogger(config: var MyConf) {.gcsafe, raises: [ConfigurationError].} =
# set up logger
discard

let c = MyConf.load(loggerSetup = myLogger)
let c = MyConf.load(onLoaded = myLogger)
```

-----------------
Expand Down Expand Up @@ -500,6 +500,24 @@ If you provide this parameter, Confutils will automatically respond
to the standard `--version` switch. If sub-commands are used, an
additional `version` top-level command will be inserted as well.

## Post processing

The `onLoaded` parameter in `load` can be used for post-processing
the configuration after it's fully populated from CLI, files, env vars, etc.
For example it can be used to setup a logger as shown in the `obsolete` [pragma
doc](#configuration-field-pragmas).

```nim
type MyConf = object
# options

proc onLoaded(config: var MyConf) {.gcsafe, raises: [ConfigurationError].} =
# Modify the config or do something else
discard

let c = MyConf.load(onLoaded = onLoaded)
```

## Compile-time options

#### `confutilsNoColors`
Expand Down
12 changes: 6 additions & 6 deletions confutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1117,8 +1117,8 @@ proc loadImpl[C, SecondarySources](
) {.gcsafe, raises: [ConfigurationError].} = nil,
envVarsPrefix = appInvocation(),
termWidth = 0,
loggerSetup: proc (
config: Configuration
onLoaded: proc (
config: var Configuration
) {.gcsafe, raises: [ConfigurationError].} = nil,
): Configuration {.raises: [ConfigurationError].} =
## Loads a program configuration by parsing command-line arguments
Expand Down Expand Up @@ -1398,9 +1398,9 @@ proc loadImpl[C, SecondarySources](
for cmd in activeCmds:
result.processMissingOpts(cmd)

if not isNil(loggerSetup):
if not isNil(onLoaded):
try:
loggerSetup(result)
onLoaded(result)
except ConfigurationError as err:
fail "Failed to setup the logger: '" & err.msg & "'"

Expand All @@ -1420,13 +1420,13 @@ template load*(
secondarySources: untyped = nil,
envVarsPrefix = appInvocation(),
termWidth = 0,
loggerSetup: untyped = nil
onLoaded: untyped = nil
): untyped =
block:
let secondarySourcesRef = generateSecondarySources(Configuration)
loadImpl(Configuration, cmdLine, version,
copyrightBanner, printUsage, quitOnFailure, ignoreUnknown,
secondarySourcesRef, secondarySources, envVarsPrefix, termWidth, loggerSetup)
secondarySourcesRef, secondarySources, envVarsPrefix, termWidth, onLoaded)

func defaults*(Configuration: type): Configuration =
load(Configuration, cmdLine = @[], printUsage = false, quitOnFailure = false)
Expand Down
1 change: 1 addition & 0 deletions tests/test_all.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import
test_nested_cmd,
test_obsolete_overload,
test_obsolete,
test_onloaded,
test_parsecmdarg,
test_pragma,
test_qualified_ident,
Expand Down
8 changes: 4 additions & 4 deletions tests/test_obsolete.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ suite "test obsolete option overload":
check registry == @["opt3", "opt3 obsolete msg"]

test "the logger setup is called":
proc loggerSetup(c: OverloadConf) =
proc onLoaded(c: var OverloadConf) =
doAssert c.opt1 == "opt1 default"
registry.add "logger"

registry.setLen 0
let conf = OverloadConf.load(loggerSetup = loggerSetup)
let conf = OverloadConf.load(onLoaded = onLoaded)
check conf.opt1 == "opt1 default"
check registry == @["logger"]

test "the logger setup is called before the overload":
proc loggerSetup(c: OverloadConf) =
proc onLoaded(c: var OverloadConf) =
doAssert c.opt1 == "foo"
registry.add "logger"

Expand All @@ -101,7 +101,7 @@ suite "test obsolete option overload":
cmdLine = @[
"--opt1=foo"
],
loggerSetup = loggerSetup
onLoaded = onLoaded
)
check conf.opt1 == "foo"
check registry == @["logger", "opt1"]
49 changes: 49 additions & 0 deletions tests/test_onloaded.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import
unittest2,
../confutils

type
TestConf = object
opt1 {.
defaultValue: "opt1 default"
name: "opt1"}: string

var registry {.threadvar.}: seq[string]

suite "test onLoaded parameter":
test "the onloaded callback is called":
proc onLoaded(c: var TestConf) =
doAssert c.opt1 == "opt1 default"
registry.add "called"

registry.setLen 0
let conf = TestConf.load(onLoaded = onLoaded)
check conf.opt1 == "opt1 default"
check registry == @["called"]

test "modify the config var":
proc onLoaded(c: var TestConf) =
doAssert c.opt1 == "foo"
c.opt1 = "foo modified"
registry.add "modified"

registry.setLen 0
let conf = TestConf.load(
cmdLine = @[
"--opt1=foo"
],
onLoaded = onLoaded
)
check conf.opt1 == "foo modified"
check registry == @["modified"]

test "use a callback closure":
var message = "closure"
proc onLoaded(c: var TestConf) {.closure.} =
doAssert c.opt1 == "opt1 default"
registry.add message

registry.setLen 0
let conf = TestConf.load(onLoaded = onLoaded)
check conf.opt1 == "opt1 default"
check registry == @["closure"]