1 # Implements script-based implementations of various namespace
4 # (c) 2011 Steve Bennett <steveb@workware.net.au>
7 proc {namespace delete
} {args
} {
9 if {$name ni
{:: ""}} {
10 set name
[uplevel 1 [list ::namespace canon
$name]]
11 foreach i
[info commands
${name
}::*] { rename $i "" }
12 uplevel #0 [list unset {*}[info globals ${name}::*]]
17 proc {namespace origin
} {name
} {
18 set nscanon
[uplevel 1 [list ::namespace canon
$name]]
19 if {[exists
-alias $nscanon]} {
20 tailcall
{namespace origin
} [info alias
$nscanon]
22 if {[exists
-command $nscanon]} {
25 if {[exists
-command $name]} {
29 return -code error "invalid command name \"$name\""
32 proc {namespace which
} {{type
-command} name
} {
33 set nsname
::[uplevel 1 [list ::namespace canon
$name]]
34 if {$type eq
"-variable"} {
37 if {$type eq
"-command"} {
38 if {[exists
-command $nsname]} {
40 } elseif
{[exists
-command ::$name]} {
45 return -code error {wrong
# args: should be "namespace which ?-command? ?-variable? name"}
49 proc {namespace code
} {arg
} {
50 if {[string first
"::namespace inscope " $arg] == 0} {
54 list ::namespace inscope
[uplevel 1 ::namespace current
] $arg
57 proc {namespace inscope
} {name arg args
} {
58 tailcall
namespace eval $name $arg $args
61 proc {namespace import
} {args
} {
62 set current
[uplevel 1 ::namespace canon
]
64 foreach pattern
$args {
65 foreach cmd
[info commands
[namespace canon
$current $pattern]] {
66 if {[namespace qualifiers
$cmd] eq
$current} {
67 return -code error "import pattern \"$pattern\" tries to import from namespace \"$current\" into itself"
69 # What if this alias would create a loop?
70 # follow the target alias chain to see if we are creating a loop
71 set newcmd
${current
}::[namespace tail
$cmd]
74 while {[exists
-alias $alias]} {
75 set alias
[info alias
$alias]
76 if {$alias eq
$newcmd} {
77 return -code error "import pattern \"$pattern\" would create a loop"
86 # namespace-aware info commands: procs, channels, globals, locals, vars
87 proc {namespace info} {cmd
{pattern
*}} {
88 set current
[uplevel 1 ::namespace canon
]
89 # Now we may need to strip $pattern
90 if {[string first
:: $pattern] == 0} {
95 set clen
[string length
$current]
98 set fqp
[namespace canon
$current $pattern]
99 switch -glob -- $cmd {
102 set result
[info $cmd $fqp]
104 # Add commands in the current namespace
106 foreach c
[info $cmd $fqp] {
107 dict
set r
[string range
$c $clen end
] 1
109 if {[string match co
* $cmd]} {
110 # Now in the global namespace
111 foreach c
[info -nons commands
$pattern] {
115 set result
[dict keys
$r]
119 set result
[info channels
$pattern]
122 #puts "uplevel #0 info gvars $fqp"
123 set result
[uplevel #0 info -nons vars $fqp]
126 set result
[info globals
$fqp]
129 set result
[uplevel 1 info -nons locals
$pattern]
133 set result
[lmap p
$result { string cat
$prefix $p }]
138 proc {namespace upvar} {ns args
} {
139 set nscanon
::[uplevel 1 [list ::namespace canon
$ns]]
140 set script
[list upvar 0]
141 foreach {other local
} $args {
142 lappend script
${nscanon
}::$other $local