In comp.lang.tcl, Larry Smith proposed on 09 Nov 2000 that
foo do-something
should be resolved, in case of no command foo being defined, like
namespace eval foo do-something
A generalized approach, using whitespace as namespace separators, was proposed in http://people.manchester.ac.uk/~zzcgudf/tcl/future.html
Reinhard Max commented: A few weeks ago, I implemented parts of that concept in pure Tcl. Maybe it's a good starting point for a more sophisticated implementation:
# # by Reinhard Max <[email protected]> # if {[info commands _unknown] eq ""} { rename unknown _unknown proc unknown {args} { # get the namespace of the caller # and set it to "" if it was the global namespace set ns [uplevel 1 namespace current] if {[string equal $ns ::]} {set ns ""} else {append ns ::} append ns [lindex $args 0] if {[catch {namespace children $ns}]} { # The namespace doesn't exist, # call the default [unknown] proc. set ret [catch {uplevel 1 _unknown $args} val] return -code $ret $val } # The namespace exists. Create a proc with the same name # for executing subcommands in this namespace ... eval [subst -nocommands { proc $ns {command args} { set code [catch { uplevel 1 ${ns}::[set command] [set args] } value] return -code [set code] [set value] } }] # ... and call it. set ret [catch {uplevel 1 $ns [lrange $args 1 end]} val] return -code $ret $val } package provide nslist 0.42 }
Usage examples and test:
tclsh8.3 > package require nslist 0.42 tclsh8.3 > namespace eval a { namespace eval b { proc c {} {puts c}}} tclsh8.3 > a b c c tclsh8.3 > a no value given for parameter "command" to "a" while evaluating a tclsh8.3 > a b no value given for parameter "command" to "a::b" while evaluating {a b}
RS: It would be even more symmetric if we could write
proc {a b c} {} {puts c}
instead of
namespace eval a { namespace eval b { proc c {} {puts c}}}
or
proc a::b::c {} {puts c}
e.g. by overloading the proc command to substitute spaces in the proc name with ::
RM: Something like that?
# # Wrapper around [proc] that allows commands inside namespaces # to be provided as {a b c} instead of a::b::c . # proc nproc {args} { set name [lindex $args 0] set ns [join [lrange $name 0 end-1] ::] set name [lindex $name end] set args [lreplace $args 0 0 _proc_ $name] set code [catch {namespace eval $ns $args} val] regsub _proc_ $val proc val return -code $code $val } rename proc _proc_ rename nproc proc
RS: I think [llength name] should be checked first: if ==1, calling the renamed _proc_ (ex proc) is sufficient.
RM: OK, here is a new version, that takes care about that. In addition, it chages the syntax to be:
proc a b c {arg1 arg2} {body}
I think this fits better to the subcommand style.
proc nproc {args} { if {[llength $args] <= 3} { set code [catch [linsert $args 0 _proc_] val] regsub _proc_ $val proc val return -code $code $val } set ns [join [lrange $args 0 end-3] ::] set args [lreplace $args 0 end-3 _proc_] set code [catch {namespace eval $ns $args} val] regsub _proc_ $val proc val return -code $code $val }