diff --git a/CHANGELOG.md b/CHANGELOG.md index 1576679f..4764c767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ 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.4.6] - 2026-07-08 + +- punk::ns 0.1.1: five development trace `puts` removed from the command doc-lookup machinery — "PROC auto def"/"ENSEMBLE auto def" from generate_autodef were emitted on STDOUT and polluted `i`/`s` output in script/exec contexts (visible to agents piping `i ` per the G-015 pattern); "skipping to documented subcommand", "cmd_traverse ensembleparam" and the "cmd_traverse 10 ... review" fallthrough note were stderr noise on the space-form-id, ensemble-parameter and undocumented-tail traverse paths. No functional change. +- punk/ns cmdflow.test: 8 new tests characterizing ensemble `-parameters` handling in the doc-lookup flow (the punk::netbox::man pattern — a leading apicontextid before the subcommand): generate_autodef models each parameter as a `-ensembleparameter 1` leader with @leaders min/max = nparams+1 (single- and two-parameter fixtures), cmd_traverse consumes parameter words and resolves the subcommand's explicit or autodef docid (re-presenting the parameter in args_remaining for the subcommand's own leader parse, matching punk::netbox::man's explicit defs), nested sub-ensembles with their own -parameters re-consume the curried parameter at each level, parse treats -ensembleparameter leaders as ordinary named leaders, and cmdhelp renders a documented subcommand's usage through the parameter. + ## [0.4.5] - 2026-07-08 - punk::args 0.2.3: fixed `@opts -any 1` (arbitrary/adhoc option passthrough) — an option not present in the definition crashed parsing with "can't read argname" instead of passing through with its value (real consumers: vendored tomlish definitions declare `-any 1`); silenced a debug `puts stderr` that fired on every failed clause type assignment (visible on any multiform parse miss). Found while building the punk::args comprehensiveness pass. diff --git a/punkproject.toml b/punkproject.toml index a7a285e0..8c8dc3a3 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,3 +1,3 @@ [project] name = "punkshell" -version = "0.4.5" +version = "0.4.6" diff --git a/src/modules/punk/ns-999999.0a1.0.tm b/src/modules/punk/ns-999999.0a1.0.tm index e37115e1..ee44fcd1 100644 --- a/src/modules/punk/ns-999999.0a1.0.tm +++ b/src/modules/punk/ns-999999.0a1.0.tm @@ -4633,7 +4633,7 @@ y" {return quirkykeyscript} set vline [punk::args::ensemble_subcommands_definition -columns 2 $origin] set autoid "(autodef)$origin" - puts "ENSEMBLE auto def $autoid (generate_autodef)" + #puts "ENSEMBLE auto def $autoid (generate_autodef)" #A namespace can contain spaces, so an ensemble command can contain spaces. We must quote the -id value in the autodef set argdef [punk::lib::tstr -return string { @id -id "${$autoid}" @@ -4699,7 +4699,7 @@ y" {return quirkykeyscript} append argdef \n "@formdisplay -body {$tepamhelp}" punk::args::define $argdef } else { - puts "PROC auto def $autoid (generate_autodef)" + #puts "PROC auto def $autoid (generate_autodef)" #to handle procs like ":" (eg used by colin's bytecode based expr replacement) or other names of the form ":xyz" #we can't use 'info args :::' - tcl won't find it set ns [nsprefix $origin] @@ -5026,7 +5026,7 @@ y" {return quirkykeyscript} if {[punk::args::id_exists "$origin [lindex $args $i]"]} { set a [lindex $args $i] #review - tests? - puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'" + #puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'" #we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent #There could be a different command at for example "${origin}::$a" which is unrelated to the actual resolution path. set docid_exists 1 @@ -5120,7 +5120,7 @@ y" {return quirkykeyscript} lappend resolvedargs $q lpop queryargs_untested 0 lappend eparams $q - puts stderr "---> cmd_traverse ensembleparam $q ($lname)" + #puts stderr "---> cmd_traverse ensembleparam $q ($lname)" #puts stderr "arginfo: $arginfo" #puts stderr "---> eparams: $eparams" #puts stderr "---> existing args: $args" @@ -5304,7 +5304,7 @@ y" {return quirkykeyscript} } } #REVIEW!!! - puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review" + #puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review" return [list 10 $origin $resolvedargs $queryargs_untested $docid] } diff --git a/src/modules/punk/ns-buildversion.txt b/src/modules/punk/ns-buildversion.txt index f47d01c8..52e3ccb7 100644 --- a/src/modules/punk/ns-buildversion.txt +++ b/src/modules/punk/ns-buildversion.txt @@ -1,3 +1,4 @@ -0.1.0 +0.1.1 #First line must be a semantic version number #all other lines are ignored. +#0.1.1 - commented out five development trace puts in the doc-lookup machinery: "PROC auto def"/"ENSEMBLE auto def" (generate_autodef - emitted on STDOUT, polluting 'i'/'s' output in script/exec contexts), "cmd_traverse - skipping to documented subcommand" (space-form id path), "---> cmd_traverse ensembleparam" (ensemble -parameters traversal), and "cmd_traverse 10 ... - review" (fallthrough return). No functional change. diff --git a/src/tests/modules/punk/ns/testsuites/ns/cmdflow.test b/src/tests/modules/punk/ns/testsuites/ns/cmdflow.test index 54d68668..cc41a8e8 100644 --- a/src/tests/modules/punk/ns/testsuites/ns/cmdflow.test +++ b/src/tests/modules/punk/ns/testsuites/ns/cmdflow.test @@ -239,5 +239,153 @@ namespace eval ::testspace { -cleanup { }\ -result [list 1 1] + + #--- ensemble -parameters / -ensembleparameter -------------------------------------------- + #Real Tcl ensembles created with 'namespace ensemble create -parameters {...}' take their + #parameter(s) BEFORE the subcommand (the punk::netbox::man pattern: 'man + #tenancy tenants list'). punk::ns::generate_autodef models each such parameter as a leader + #marked -ensembleparameter 1 in the (autodef) definition, and the cmd_traverse doc walk + #consumes parameter words before resolving the subcommand - re-presenting the parameter in + #args_remaining so the subcommand's own definition (which models the curried parameter as + #a normal leader, as punk::netbox::man's explicit defs do) can parse it for goodargs + #marking in cmdhelp. + + #fixture: single-parameter ensemble; sub1 explicitly documented, sub2 not + namespace eval paramens { + namespace export {[a-z]*} + namespace ensemble create -parameters {apicontextid} + proc sub1 {apicontextid args} {} + proc sub2 {apicontextid args} {} + } + punk::args::define { + @id -id ::testspace::paramens::sub1 + @cmd -name "testspace::paramens sub1" -summary "paramens sub1 summary" -help "paramens sub1 help" + @leaders -min 1 -max 1 + apicontextid -type string -help "context id (curried ensemble parameter)" + @values -min 0 -max 0 + } + + #fixture: nested sub-ensemble with its own -parameters (netbox tenancy/tenants pattern) + namespace eval paramens2 { + namespace export {[a-z]*} + namespace eval nest { + namespace export {[a-z]*} + namespace ensemble create -parameters {apicontextid} + proc leafcmd {apicontextid args} {} + } + namespace ensemble create -parameters {apicontextid} + } + + #fixture: two leading parameters + namespace eval paramens3 { + namespace export {[a-z]*} + namespace ensemble create -parameters {p1 p2} + proc s1 {p1 p2 args} {} + } + + test ensparam_autodef_structure {ensemble autodef models -parameters as -ensembleparameter leaders before the subcommand}\ + -setup $common -body { + #cmdinfo triggers autodef generation for the ensemble root + set cinfo [punk::ns::cmdinfo ::testspace::paramens] + lappend result [dict get $cinfo docid] + set spec [punk::args::get_spec (autodef)::testspace::paramens] + set fid [lindex [dict get $spec form_names] 0] + set lnames [dict get $spec FORMS $fid LEADER_NAMES] + lappend result $lnames + foreach ln $lnames { + lappend result [punk::args::system::Dict_getdef [dict get $spec FORMS $fid ARG_INFO $ln] -ensembleparameter 0] + } + lappend result [dict get $spec FORMS $fid LEADER_MIN] [dict get $spec FORMS $fid LEADER_MAX] + }\ + -cleanup { + }\ + -result [list\ + (autodef)::testspace::paramens\ + {apicontextid subcommand}\ + 1 0\ + 2 2\ + ] + + test ensparam_autodef_two_parameters {an ensemble with two -parameters gets two -ensembleparameter leaders and min/max = nparams+1}\ + -setup $common -body { + set cinfo [punk::ns::cmdinfo ::testspace::paramens3 pv1 pv2 s1] + lappend result [dict get $cinfo docid] + set spec [punk::args::get_spec (autodef)::testspace::paramens3] + set fid [lindex [dict get $spec form_names] 0] + lappend result [dict get $spec FORMS $fid LEADER_NAMES] + lappend result [dict get $spec FORMS $fid LEADER_MIN] [dict get $spec FORMS $fid LEADER_MAX] + }\ + -cleanup { + }\ + -result [list\ + (autodef)::testspace::paramens3::s1\ + {p1 p2 subcommand}\ + 3 3\ + ] + + test ensparam_traverse_to_documented_sub {the doc walk consumes the parameter word and resolves the subcommand's explicit docid}\ + -setup $common -body { + set cinfo [punk::ns::cmdinfo ::testspace::paramens ctxA sub1] + lappend result [dict get $cinfo docid] + #the parameter is re-presented in args_remaining for the subcommand's own parse + lappend result [dict get $cinfo args_remaining] + lappend result [dict get $cinfo args_resolved] + }\ + -cleanup { + }\ + -result [list\ + ::testspace::paramens::sub1\ + ctxA\ + {::testspace::paramens ctxA sub1}\ + ] + + test ensparam_traverse_to_undocumented_sub {the doc walk reaches an autodef for an undocumented subcommand through the parameter}\ + -setup $common -body { + set cinfo [punk::ns::cmdinfo ::testspace::paramens ctxA sub2] + lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining] + }\ + -cleanup { + }\ + -result [list (autodef)::testspace::paramens::sub2 ctxA] + + test ensparam_param_without_subcommand {a parameter word with no subcommand stays at the ensemble root docid}\ + -setup $common -body { + set cinfo [punk::ns::cmdinfo ::testspace::paramens ctxA] + lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining] + }\ + -cleanup { + }\ + -result [list (autodef)::testspace::paramens {}] + + test ensparam_nested_subensemble {parameters are consumed at each ensemble level when sub-ensembles have their own -parameters}\ + -setup $common -body { + #real invocation: 'paramens2 ctxA nest leafcmd ...' - the map re-curries ctxA into + #the nest sub-ensemble, whose own -parameters consumes it again + set cinfo [punk::ns::cmdinfo ::testspace::paramens2 ctxA nest leafcmd] + lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining] + }\ + -cleanup { + }\ + -result [list (autodef)::testspace::paramens2::nest::leafcmd ctxA] + + test ensparam_parse_autodef_leaders {punk::args::parse treats -ensembleparameter leaders as ordinary named leaders}\ + -setup $common -body { + #ensure the autodef exists + punk::ns::cmdinfo ::testspace::paramens + set argd [punk::args::parse {ctxA sub1} withid (autodef)::testspace::paramens] + lappend result [dict get $argd leaders] + }\ + -cleanup { + }\ + -result [list {apicontextid ctxA subcommand sub1}] + + test ensparam_cmdhelp_string_smoke {cmdhelp renders the documented subcommand's usage through the ensemble parameter}\ + -setup $common -body { + set out [punk::ns::cmdhelp -return string ::testspace::paramens ctxA sub1] + lappend result [string match "*paramens sub1 summary*" $out] + }\ + -cleanup { + }\ + -result [list 1] } tcltest::cleanupTests ;#needed to produce test summary line.