Browse Source

commandstack 0.8.0: rename_command -punkargs stack-tied doc blocks (G-176 increment 3; project 0.64.0)

rename_command accepts a new leading option '-punkargs
<list-of-definitionlists>' attaching punk::args doc blocks to the
rename's stack record - e.g documenting a subcommand the override adds,
with space-form ids such as {::package epoch}. Each element is one
definitionlist exactly as given to punk::args::define (the same shape as
a PUNKARGS variable element).

Lifecycle: docs attach only when the rename lands (aborted renames
return early) and are LIVE while the record is on the stack. The detach
hook sits at remove_rename's doomed-record site - pop_rename,
remove_renamer and restore_original all funnel through it - so every
removal path removes the docs with the record.

Works whether or not punk::args is loaded at rename time: deflists are
mirrored in a new ::commandstack::stackdocs namespace registered inert
into ::punk::args::register::NAMESPACES at module load (punk::args need
not be present - the early-boot renames precede it), so a later-loading
punk::args picks them up lazily; when punk::args is already present they
are ALSO defined immediately (a namespace already consumed into
loaded_packages never lazy-loads later appends; redefinition is
idempotent). Detach removes one mirror occurrence per deflist and
undefines via punk::args::undefine_deflist (deflist-keyed - commandstack
never parses ids; never-defined deflists skip silently). Supported
shape: one live record per doc id (same-id declarations in two records
shadow; removing either removes the doc).

The record carries the deflists under a trailing 'punkargs' key - the
append-only key-order contract is preserved (token idx 0-1, renamer idx
2-3). The leading-option parse is generalised: -renamer/-punkargs in
either order, both leading-only, non-dash word ends option scanning so
misplaced options raise the pointed error. stackdocs state follows the
0.7.1 reload contract (info-exists guarded; registration idempotent
across re-source). commandstack::help and the rename_command argdoc
document the mechanism; the In-tree users line gains punk::libunknown
(the increment-2 migration).

commandstack.test: 5 new pins (docs live with the record incl key-order
assertions, all four removal paths detach, the pre-punk::args pending
path in a bare child that loads punk::args afterwards and lazily
consumes the registered mirror, reload contract on mirror + single
registration, option positions in either order + pointed misplacement) +
2 existing G-160 message pins updated to the generalised
usage/misplacement wording (behaviour contracts unchanged). Suite 46/46.

src/tests/modules/AGENTS.md commandstack bullet updated; goal Progress
entry added. Project 0.63.0 -> 0.64.0 + CHANGELOG.

Suites: commandstack 46/46; full modules tree 1351 total / 1340 pass /
11 constraint-skipped / 0 fail (zig-built tclsh90s 9.0.5);
testbody_lint 1704 clean; goals_lint clean (80 active-index / 96
archived); make.tcl projectversion consistency OK.

Claude-Session: https://claude.ai/code/session_01QgaxV27VZkmEec7oNbEVFc
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 2 days ago
parent
commit
ad0489b881
  1. 16
      CHANGELOG.md
  2. 25
      goals/G-176-commandstack-doc-integration.md
  3. 2
      punkproject.toml
  4. 155
      src/modules/commandstack-999999.0a1.0.tm
  5. 3
      src/modules/commandstack-buildversion.txt
  6. 2
      src/tests/modules/AGENTS.md
  7. 154
      src/tests/modules/commandstack/testsuites/commandstack/commandstack.test

16
CHANGELOG.md

@ -5,6 +5,22 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.64.0] - 2026-08-08
- `commandstack` 0.8.0 (G-176 increment 3): `rename_command` accepts a new
leading option `-punkargs <list-of-definitionlists>` attaching punk::args
doc blocks to the rename's stack record - e.g documenting a subcommand
the override adds, with space-form ids such as `{::package epoch}`. The
docs are live while the record is on the stack and are removed with it
by ANY removal path (`remove_rename`, `pop_rename`, `remove_renamer`,
`restore_original`). Renames performed before punk::args loads are
supported: definitions are mirrored in the registered
`::commandstack::stackdocs` namespace and load lazily with punk::args;
when punk::args is already present they are defined immediately. The
record carries the deflists under a trailing `punkargs` key (key-order
contract preserved); `commandstack::help` and the `rename_command`
argdoc describe the mechanism.
## [0.63.0] - 2026-08-08
- `punk::libunknown` 0.3.0 (G-176 increment 2): the `::package` override

25
goals/G-176-commandstack-doc-integration.md

@ -145,6 +145,31 @@ Increments land as separate commits, each leaving all suites green:
parent paths and needed no changes. Suites: libunknown tree + loadedlib 42/42;
full modules tree green. Project 0.63.0.
- Increment 3 (-punkargs stack-tied docs) landed 2026-08-08: commandstack 0.8.0.
rename_command takes a leading '-punkargs <list-of-definitionlists>' (each
element one definitionlist as given to punk::args::define - the same shape as
a PUNKARGS variable element; the leading-option parse is generalised, -renamer
and -punkargs in either order, both leading-only with pointed misplacement
errors). Docs attach on a landed rename only: record gains a TRAILING
'punkargs' key (key-order contract intact), deflists are mirrored in the new
reload-guarded ::commandstack::stackdocs namespace (registered inert into
::punk::args::register::NAMESPACES at module load - punk::args need not
exist) and are ALSO defined immediately when punk::args is present (a
namespace already consumed into loaded_packages never lazy-loads later
appends; redefinition idempotent - a define error surfaces to the caller with
the rename installed). Detach lives in remove_rename's doomed-record site -
pop_rename/remove_renamer/restore_original all funnel through it - removing
one mirror occurrence per deflist and undefining via
punk::args::undefine_deflist (deflist-keyed; never-defined deflists skip
silently). One live record per doc id is the documented shape.
commandstack::help + the rename_command argdoc carry the how-to; In-tree
users line gains punk::libunknown. 5 new commandstack.test pins (docs live
with record incl key order, all four removal paths detach, the pre-punk::args
pending path in a bare child loading punk::args afterwards, reload contract
on the mirror + single registration, option positions) + 2 G-160 message pins
updated to the generalised usage/misplacement wording. Suite 46/46. Project
0.64.0.
## Follow-ons
- Boot-site commandstack pre-sourcing (out of the current Scope - a Scope

2
punkproject.toml

@ -1,6 +1,6 @@
[project]
name = "punkshell"
version = "0.63.0"
version = "0.64.0"
license = "BSD-2-Clause"
url = "https://www.gitea1.intx.com.au/jn/punkshell"
#packager: declared identity for published artifacts (declarative, not proof -

155
src/modules/commandstack-999999.0a1.0.tm

@ -107,6 +107,30 @@ namespace eval commandstack {
}
}
namespace eval commandstack::stackdocs {
#Doc blocks attached by 'rename_command -punkargs' for LIVE stack records
#(G-176): PUNKARGS mirrors those records' punk::args definitionlists so a
#punk::args that loads AFTER the renames (early-boot renames precede it)
#picks them up lazily via the ::punk::args::register::NAMESPACES mechanism.
#Maintained by rename_command (attach) and remove_rename (detach - every
#removal path funnels through it). Guarded per the reload contract.
variable PUNKARGS
if {![info exists PUNKARGS]} {
set PUNKARGS [list]
}
}
namespace eval ::punk::args::register {
#inert registration - consumed if/when punk::args loads (idempotent across
#re-source; punk::args need not be present)
variable NAMESPACES
if {![info exists NAMESPACES]} {
set NAMESPACES [list]
}
if {"::commandstack::stackdocs" ni $NAMESPACES} {
lappend NAMESPACES ::commandstack::stackdocs
}
}
namespace eval commandstack::util {
#note - we can't use something like md5 to ID proc body text because we don't want to require additional packages.
#We could store the full text of the body to compare - but we need to identify magic strings from cooperating packages such as packageTrace
@ -220,6 +244,22 @@ namespace eval commandstack {
commandstack::next {*}$args
The record also carries a trailing did_rename 0|1 verdict.
set record [commandstack::rename_command -renamer <mypkg> -punkargs <deflists> <command> <procargs> <procbody>]
As above, additionally attaching punk::args doc blocks to the stack
record - each <deflists> element is one definitionlist exactly as
given to punk::args::define (e.g documenting a subcommand the
override adds, with a space-form id such as {::package epoch}).
The docs are live while the record is on the stack and are removed
with it by ANY removal path (remove_rename, pop_rename,
remove_renamer, restore_original). Renames performed BEFORE
punk::args loads are supported: definitions are mirrored in the
registered ::commandstack::stackdocs namespace and load lazily with
punk::args; when punk::args is already loaded they are defined
immediately. Use one live record per doc id - same-id declarations
in two records shadow each other, and removing either removes the
doc. The record carries the attached deflists under a trailing
punkargs key.
commandstack::remove_rename <token_or_command>
Undo a rename. Accepts the token from the rename record
([dict get $record token] = {<command> <renamer> <tokenid>}),
@ -268,8 +308,9 @@ namespace eval commandstack {
`i commandstack::rename_command` in punkshell, or
`punk::args::usage ::commandstack::rename_command` when punk::args is loaded.
In-tree users: punk::packagepreference, punk::nav::fs, punk (auto_execok),
packagetrace, packagesuppress.
In-tree users: punk::packagepreference, punk::libunknown (the ::package
epoch/forget override), punk::nav::fs, punk (auto_execok), packagetrace,
packagesuppress.
}
}
@ -458,6 +499,7 @@ namespace eval commandstack {
Returns the new stack record - a dict with keys:
token renamer next_implementor next_getter implementation did_rename
(plus a trailing punkargs key when -punkargs was given).
The tokenid (third token element) is unique and monotonic per
(renamer, command) pairing, so repeat renames by the same
renamer are individually addressable. When no rename was
@ -475,8 +517,28 @@ namespace eval commandstack {
"Identity string recorded for this rename - defaults to
the calling namespace. Cooperating packages use their
package/namespace name. Note: this flag is recognised
only as the FIRST argument (manual parse) - appearing
in any later position is an error."
only in the leading option positions (manual parse) -
appearing after the positional arguments begin is an
error."
-punkargs -type list -optional 1 -typesynopsis {list-of-definitionlists} -help -&
"punk::args doc blocks attached to this rename's stack
record - each element is one definitionlist exactly as
given to punk::args::define (e.g documenting a
subcommand the override adds, with a space-form id
such as {::package epoch}). The docs are live while
the record is on the stack and are removed with it by
ANY removal path (remove_rename, pop_rename,
remove_renamer, restore_original). Renames performed
BEFORE punk::args loads are supported: the definitions
are mirrored in the registered
::commandstack::stackdocs namespace and load lazily
with punk::args (keep such deflists free of
dollar-brace tstr substitutions needing your own
namespace context - the lazy load evaluates them in
the stackdocs namespace).
Use one live record per doc id: same-id declarations
in two records shadow each other. Recognised only in
the leading option positions, like -renamer."
@values -min 3 -max 3
command -type string -help -&
"Command to rename (resolved with 'namespace which' in
@ -493,18 +555,31 @@ namespace eval commandstack {
#todo: consider -forcebase 1 or similar to allow this rename to point to bottom of stack (original command) bypassing existing renames
# - need to consider that upon removing, that any remaining rename that was higher on the stack should not also be diverted to the base - but rather to the next lower in the stack
#
if {[lindex $args 0] eq "-renamer"} {
set renamer [lindex $args 1]
set arglist [lrange $args 2 end]
} else {
set renamer ""
set arglist $args
set renamer ""
set punkargs_defs [list]
set arglist $args
while {[llength $arglist] > 3 && [string match -* [lindex $arglist 0]]} {
switch -- [lindex $arglist 0] {
-renamer {
set renamer [lindex $arglist 1]
set arglist [lrange $arglist 2 end]
}
-punkargs {
set punkargs_defs [lindex $arglist 1]
set arglist [lrange $arglist 2 end]
}
default {
error "commandstack::rename_command unrecognised leading option '[lindex $arglist 0]'. usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody"
}
}
}
if {"-renamer" in $arglist} {
error "commandstack::rename_command -renamer is recognised only as the leading argument. usage: rename_command ?-renamer <string>? command procargs procbody"
foreach opt {-renamer -punkargs} {
if {$opt in $arglist} {
error "commandstack::rename_command $opt is recognised only in the leading option positions. usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody"
}
}
if {[llength $arglist] != 3} {
error "commandstack::rename_command usage: rename_command ?-renamer <string>? command procargs procbody"
error "commandstack::rename_command usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody"
}
lassign $arglist command procargs procbody
@ -646,6 +721,12 @@ namespace eval commandstack {
}
return [dict create implementation "" did_rename 0]
}
if {[llength $punkargs_defs]} {
#additive key - appended after the leading key-order contract keys
#(token idx 0-1, renamer idx 2-3); docs attach only for a rename
#that actually lands (aborted renames returned above)
dict set new_record punkargs $punkargs_defs
}
catch {rename ::commandstack::temp::testproc ""}
set nextinit [string map [list %command% $command %renamer% $renamer %next_getter% [dict get $new_record next_getter] %original_implementation% [dict get $new_record implementation]] {
#IMPLEMENTOR_%renamer%! (mechanism: 'commandstack::rename_command -renamer %renamer% %command% <procargs> <procbody> )
@ -661,10 +742,52 @@ namespace eval commandstack {
uplevel 1 [list rename ::commandstack::temp::testproc $command]
dict lappend all_stacks $command $new_record
dict set token_implementations [dict get $nextinfo token] [dict get $nextinfo next_target]
if {[llength $punkargs_defs]} {
Stackdocs_attach $punkargs_defs
}
return $new_record
}
#G-176: doc blocks attached to stack records via 'rename_command -punkargs'.
#Attach appends each definitionlist to the commandstack::stackdocs PUNKARGS
#mirror (consumed lazily if punk::args loads later - the namespace is
#registered inert at module load) and defines immediately when punk::args
#is already present (a namespace already consumed into punk::args'
#loaded_packages never lazy-loads later appends; redefining an unchanged id
#is idempotent - a define error surfaces to the rename_command caller with
#the rename already installed, inspectable via show_stack). Detach removes
#ONE mirror occurrence per deflist and undefines via
#punk::args::undefine_deflist (deflist-keyed; silently skips never-defined
#deflists). One live record per doc id is the supported shape - two records
#declaring the same id shadow each other and removing either removes the
#doc.
proc Stackdocs_attach {deflists} {
foreach deflist $deflists {
lappend ::commandstack::stackdocs::PUNKARGS $deflist
if {[llength [info commands ::punk::args::define]]} {
punk::args::define {*}$deflist
}
}
return
}
proc Stackdocs_detach {deflists} {
variable debug
upvar 0 ::commandstack::stackdocs::PUNKARGS docmirror
foreach deflist $deflists {
set posn [lsearch -exact $docmirror $deflist]
if {$posn > -1} {
set docmirror [lreplace $docmirror $posn $posn]
}
if {[llength [info commands ::punk::args::undefine_deflist]]} {
if {[catch {punk::args::undefine_deflist $deflist} errM] && $debug} {
puts stderr "(commandstack::Stackdocs_detach) WARNING: undefine_deflist failed: $errM"
}
}
}
return
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::commandstack::next
@ -800,6 +923,12 @@ namespace eval commandstack {
set stack [lreplace $stack $doomed_posn $doomed_posn]
dict set all_stacks $command $stack
dict unset token_implementations [dict get $doomed_record token]
if {[dict exists $doomed_record punkargs]} {
#G-176: docs attached with 'rename_command -punkargs' die with
#the record. Every removal path (pop_rename/remove_renamer/
#restore_original) funnels through here.
Stackdocs_detach [dict get $doomed_record punkargs]
}
}
return $stack

3
src/modules/commandstack-buildversion.txt

@ -1,6 +1,7 @@
0.7.1
0.8.0
#First line must be a tm version number
#all other lines are ignored.
#0.8.0 - G-176 increment 3: rename_command accepts a new leading option '-punkargs <list-of-definitionlists>' attaching punk::args doc blocks to the rename's stack record (e.g documenting a subcommand the override adds, space-form ids like {::package epoch} supported). The docs are LIVE while the record is on the stack and are removed with it by ANY removal path - the detach hook sits in remove_rename, which pop_rename/remove_renamer/restore_original all funnel through. Works whether or not punk::args is loaded at rename time: deflists are mirrored in a new registered ::commandstack::stackdocs namespace (inert ::punk::args::register::NAMESPACES registration at module load - punk::args need not be present) so a later-loading punk::args picks them up lazily; when punk::args is already present they are ALSO defined immediately (a namespace already consumed into loaded_packages never lazy-loads later appends; redefinition is idempotent). Detach removes one mirror occurrence per deflist and undefines via punk::args::undefine_deflist (deflist-keyed - commandstack never parses ids; silently skips never-defined deflists). Record carries the deflists under a trailing 'punkargs' key (append-only key-order contract preserved: token idx 0-1, renamer idx 2-3). Supported shape: one live record per doc id (same-id declarations in two records shadow; removing either removes the doc). Leading-option parse generalised (-renamer/-punkargs in either order, both leading-only). stackdocs state follows the reload contract (info-exists guarded). help + rename_command argdoc document the how-to; In-tree users line gains punk::libunknown (the increment-2 migration). Pins: commandstack.test -punkargs lifecycle (docs live with record + removed by all four removal paths + pre-punk::args pending path in a bare child that loads punk::args afterwards + key-order/reload guards).
#0.7.1 - G-160 follow-on: reload contract - known_renamers and debug are now
# info-exists guarded like the rest of the module state (all_stacks,
# renamer_command_tokens, token_implementations): a module re-source no

2
src/tests/modules/AGENTS.md

File diff suppressed because one or more lines are too long

154
src/tests/modules/commandstack/testsuites/commandstack/commandstack.test

@ -47,6 +47,16 @@
# token_implementations, known_renamers and debug are each info-exists
# guarded, so a reload can never strand live stacks by resetting the
# state that references them.
# 8. Stack-tied doc blocks (0.8.0, G-176 increment 3): 'rename_command
# -punkargs <list-of-definitionlists>' attaches punk::args docs to the
# record (trailing 'punkargs' key - leading key order unchanged), live
# while the record is on the stack and removed by EVERY removal path
# (remove_rename/pop_rename/remove_renamer/restore_original all funnel
# through the remove_rename detach hook). Renames performed BEFORE
# punk::args loads mirror the deflists in the registered
# ::commandstack::stackdocs namespace for lazy pickup; the mirror and its
# registration follow the reload contract. Both leading options accepted
# in either order; misplaced options raise the pointed error.
#
# Tests run against the SOURCE-TREE module. Behavioural tests use a fresh
# child interp per test (sourcing the module by path) so that: module state
@ -431,27 +441,31 @@ namespace eval ::testspace {
}
} -result {{implementation {} did_rename 0} 0 {implementation {} did_rename 0} 0 1}
#usage text updated 0.8.0 (G-176 increment 3) - the -punkargs leading option
#joined the synopsis
test commandstack_rename_command_usage_error {rename_command arg-count validation message is pinned}\
-constraints commandstacksrc -body {
cs_probe {
catch {commandstack::rename_command ::whatever} msg
set msg
}
} -result {commandstack::rename_command usage: rename_command ?-renamer <string>? command procargs procbody}
} -result {commandstack::rename_command usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody}
#added 2026-08-03 (agent, G-160)
#-renamer is recognised only as the leading argument - anywhere else it now
#-renamer is recognised only in the leading option positions - anywhere else it
#errors instead of being silently consumed as the command/procargs/procbody
#value (the historical misparse: 'rename_command ::tgt -renamer ::x' treated
#-renamer as the procargs). The stack stays untouched in both error forms.
test commandstack_renamer_flag_misplacement_errors {rename_command errors when -renamer appears anywhere but the leading position}\
#Message wording updated 0.8.0 (G-176 increment 3) with the generalised
#leading-option parse ('leading option positions' - -punkargs joined -renamer).
test commandstack_renamer_flag_misplacement_errors {rename_command errors when -renamer appears anywhere but the leading positions}\
-constraints commandstacksrc -body {
cs_probe {
proc ::tgt {args} {return [list base $args]}
set c1 [catch {commandstack::rename_command ::tgt {args} {return x} -renamer ::csA} msg1]
set c2 [catch {commandstack::rename_command ::tgt -renamer ::csA} msg2]
list $c1 [string match "*-renamer is recognised only as the leading argument*" $msg1] \
$c2 [string match "*-renamer is recognised only as the leading argument*" $msg2] \
list $c1 [string match "*-renamer is recognised only in the leading option position*" $msg1] \
$c2 [string match "*-renamer is recognised only in the leading option position*" $msg2] \
[dict size [commandstack::get_stack]]
}
} -result {1 1 1 1 0}
@ -1038,5 +1052,135 @@ namespace eval ::testspace {
}
} -result {{b1 q} {b2 q} 0}
#added 2026-08-08 (agent, G-176 increment 3) - stack-tied doc blocks:
#'rename_command -punkargs' attaches punk::args definitionlists to the record.
#Children needing punk::args derive the source-modules dir from
#::COMMANDSTACK_SRC and require it prefer-latest (999999 dev copy).
#docs live with the record: -punkargs defines immediately when punk::args is
#present, the record carries a TRAILING punkargs key (leading key-order
#contract intact - token/renamer lsearch indices unchanged), and
#remove_rename removes the doc and its stackdocs mirror entry with the record.
test commandstack_punkargs_docs_live_with_record {-punkargs docs defined at rename (punk::args loaded), trailing record key, removed with the record by remove_rename}\
-constraints commandstacksrc -body {
cs_probe {
tcl::tm::add [file dirname $::COMMANDSTACK_SRC]
package prefer latest
package require punk::args
proc ::tgt {args} {return [list base $args]}
set rec [commandstack::rename_command -renamer ::csA -punkargs {{{@id -id {::tgt extra}
@cmd -name "override: tgt extra" -summary "extra subcommand." -help "extra subcommand help."
@values -min 0 -max 0}}} ::tgt {args} {
return [list A [uplevel 1 [list $COMMANDSTACKNEXT {*}$args]]]
}]
set r [list]
lappend r [lindex [dict keys $rec] 0] [lindex [dict keys $rec] 1] [lindex [dict keys $rec] end]
lappend r [expr {[lsearch -index 1 [commandstack::get_stack ::tgt] [dict get $rec token]] >= 0}]
lappend r [expr {[lsearch -index 3 [commandstack::get_stack ::tgt] ::csA] >= 0}]
lappend r [punk::args::id_exists {::tgt extra}]
lappend r [llength $::commandstack::stackdocs::PUNKARGS]
lappend r [::tgt x]
commandstack::remove_rename [dict get $rec token]
lappend r [punk::args::id_exists {::tgt extra}]
lappend r [llength $::commandstack::stackdocs::PUNKARGS]
lappend r [::tgt x]
set r
}
} -result {token renamer punkargs 1 1 1 1 {A {base x}} 0 0 {base x}}
#every removal path detaches: pop_rename, remove_renamer and restore_original
#all funnel through remove_rename's detach hook.
test commandstack_punkargs_all_removal_paths_detach {pop_rename, remove_renamer and restore_original each remove the attached doc}\
-constraints commandstacksrc -body {
cs_probe {
tcl::tm::add [file dirname $::COMMANDSTACK_SRC]
package prefer latest
package require punk::args
proc ::tgt {args} {return [list base $args]}
set DEFS {{{@id -id {::tgt extra}
@cmd -name "override: tgt extra" -summary "extra subcommand." -help "extra subcommand help."
@values -min 0 -max 0}}}
set r [list]
foreach removal {
{commandstack::pop_rename ::csA ::tgt}
{commandstack::remove_renamer ::csA}
{commandstack::restore_original ::tgt}
} {
commandstack::rename_command -renamer ::csA -punkargs $DEFS ::tgt {args} {
uplevel 1 [list $COMMANDSTACKNEXT {*}$args]
}
lappend r [punk::args::id_exists {::tgt extra}]
eval $removal
lappend r [punk::args::id_exists {::tgt extra}] [llength $::commandstack::stackdocs::PUNKARGS]
}
set r
}
} -result {1 0 0 1 0 0 1 0 0}
#the early-boot shape: the rename happens BEFORE punk::args exists - the
#deflists sit in the registered stackdocs mirror, punk::args picks them up
#lazily (update_definitions on the registered namespace), and a pop still
#removes the by-then-defined doc.
test commandstack_punkargs_pending_before_punkargs_loads {-punkargs before punk::args loads: mirrored, lazily defined when punk::args arrives, removed on pop}\
-constraints commandstacksrc -body {
cs_probe {
proc ::tgt {args} {return [list base $args]}
commandstack::rename_command -renamer ::csA -punkargs {{{@id -id {::tgt zap}
@cmd -name "override: tgt zap" -summary "zap subcommand." -help "zap subcommand help."
@values -min 0 -max 0}}} ::tgt {args} {
uplevel 1 [list $COMMANDSTACKNEXT {*}$args]
}
set r [list]
lappend r [llength [info commands ::punk::args::define]] [llength $::commandstack::stackdocs::PUNKARGS]
tcl::tm::add [file dirname $::COMMANDSTACK_SRC]
package prefer latest
package require punk::args
punk::args::update_definitions [list ::commandstack::stackdocs]
lappend r [punk::args::id_exists {::tgt zap}]
commandstack::pop_rename ::csA ::tgt
lappend r [punk::args::id_exists {::tgt zap}] [llength $::commandstack::stackdocs::PUNKARGS]
set r
}
} -result {0 1 1 0 0}
#reload contract extends to the new state: a re-source with a live attached
#doc preserves the stackdocs mirror and does not duplicate the inert
#::punk::args::register::NAMESPACES registration.
test commandstack_punkargs_reload_contract {module re-source preserves the stackdocs mirror and keeps the registration single}\
-constraints commandstacksrc -body {
cs_probe {
proc ::tgt {args} {return [list base $args]}
commandstack::rename_command -renamer ::csA -punkargs {{{@id -id {::tgt extra}
@cmd -name "override: tgt extra" -summary "extra subcommand." -help "extra subcommand help."
@values -min 0 -max 0}}} ::tgt {args} {
uplevel 1 [list $COMMANDSTACKNEXT {*}$args]
}
source $::COMMANDSTACK_SRC
set r [list]
lappend r [llength $::commandstack::stackdocs::PUNKARGS]
lappend r [llength [lsearch -all -exact $::punk::args::register::NAMESPACES ::commandstack::stackdocs]]
commandstack::restore_original ::tgt
lappend r [llength $::commandstack::stackdocs::PUNKARGS] [::tgt x]
set r
}
} -result {1 1 0 {base x}}
#leading options parse in either order; an option after the positional
#arguments begin raises the pointed misplacement error.
test commandstack_punkargs_option_positions {-renamer/-punkargs accepted in either leading order; misplaced option raises the pointed error}\
-constraints commandstacksrc -body {
cs_probe {
proc ::tgt {args} {return [list base $args]}
set rec [commandstack::rename_command -punkargs {} -renamer ::csA ::tgt {args} {
uplevel 1 [list $COMMANDSTACKNEXT {*}$args]
}]
set r [list]
lappend r [dict get $rec did_rename] [dict exists $rec punkargs]
lappend r [catch {commandstack::rename_command ::tgt -punkargs {x} {args}} m]
lappend r [string match "*leading option position*" $m]
set r
}
} -result {1 0 1 1}
cleanupTests
}

Loading…
Cancel
Save