Index: modules/namespacex/namespacex.man ================================================================== --- modules/namespacex/namespacex.man +++ modules/namespacex/namespacex.man @@ -1,7 +1,8 @@ +[vset VERSION 0.2] [comment {-*- tcl -*- doctools manpage}] -[manpage_begin namespacex n 0.1] +[manpage_begin namespacex n [vset VERSION]] [keywords {extended namespace}] [keywords info] [keywords {namespace unknown}] [keywords {namespace utilities}] [keywords {state (de)serialization}] @@ -11,63 +12,163 @@ [copyright {200? Various (http://wiki.tcl.tk/1489)}] [copyright {2010 Documentation, Andreas Kupries}] [moddesc {Namespace utility commands}] [titledesc {Namespace utility commands}] [require Tcl 8.5] -[require namespacex [opt 0.1]] +[require namespacex [opt [vset VERSION]]] [description] This package provides a number of utility commands for working with namespaces. -[section API] +The commands fall into four categories: + +[list_begin enumerated] + +[enum] Hook commands provide and manipulate a chain of commands which +replaces the single regular [cmd "namespace unknown"] handler. + +[enum] An import command provides the ability to import any command +from another namespace. + +[enum] Information commands allow querying of variables and child +namespaces. + +[enum] State commands provide a means to serialize variable values in +a namespace. + +[list_end] + +[section Commands] [list_begin definitions] [call [cmd {::namespacex hook add}] [opt [arg namespace]] [arg cmdprefix]] -[call [cmd {::namespacex hook proc}] [opt [arg namespace]] [arg arguments] [arg body]] -[call [cmd {::namespacex hook on}] [opt [arg namespace]] [arg guardcmdprefix] [arg actioncmdprefix]] + +Adds the [arg cmdprefix] to the chain of unknown command handlers that +are invoked when the [arg namespace] would otherwise invoke its +unknown handler. + +If [arg namespace] is not specified, then [arg cmdprefix] is added to +the chain of handlers for the namespace of the caller. + +[para] +The chain of [arg cmdprefix] are executed in reverse order of +addition, [emph i.e.] the most recently added [arg cmdprefix] is +executed first. + +When executed, [arg cmdprefix] has additional arguments appended to it +as would any namespace unknown handler. + +[call [cmd {::namespacex hook proc}] [opt [arg namespace]] \ + [arg arguments] [arg body]] + +Adds an anonymous procedure to the chain of namespace unknown handlers +for the [arg namespace]. + +[para] If [arg namespace] is not specified, then the handler is added +to the chain of handlers for the namespace of the caller. + +[para] The [arg arguments] and [arg body] are specified as for the +core [cmd proc] command. + +[call [cmd {::namespacex hook on}] [opt [arg namespace]] \ + [arg guardcmdprefix] [arg actioncmdprefix]] + +Adds a guarded action to the chain of namespace unknown handlers for +the [arg namespace]. + +[para] If [arg namespace] is not specified, then the handler is added +to the chain of handlers for the namespace of the caller. + +[para] The [arg guardcmdprefix] is executed first. If it returns a +value that can be interpreted as false, then the next unknown hander +in the chain is executed. Otherwise, [arg actioncmdprefix] is executed +and the return value of the handler is the value returned by +[arg actioncmdprefix]. + +[para] When executed, both [arg guardcmdprefix] and +[arg actioncmdprefix] have the same additional arguments appended as +for any namespace unknown handler. + [call [cmd {::namespacex hook next}] [arg arg]...] + +This command is available to namespace hooks to execute the next hook +in the chain of handlers for the namespace. + +[call [cmd {::namespacex import fromns}] [arg "cmdname [opt "[arg newname] ..."]"]] + +Imports the command [arg cmdname] from the [arg fromns] namespace into +the namespace of the caller. + +The [arg cmdname] command is imported even if the [arg fromns] did not +originally export the command. + +[para] If [arg newname] is specified, then the imported command will +be known by that name. Otherwise, the command retains is original name +as given by [arg cmdname]. + +[para] Additional pairs of [arg cmdname] / [arg newname] arguments may +also be specified. [call [cmd {::namespacex info allchildren}] [arg namespace]] -This command returns a list containing the names of all child -namespaces in the specified [arg namespace] and its children. The -names are all fully qualified. +Returns a list containing the names of all child namespaces in the +specified [arg namespace] and its children. The names are all fully +qualified. [call [cmd {::namespacex info allvars}] [arg namespace]] -This command returns a list containing the names of all variables in -the specified [arg namespace] and its children. The names are all -relative to [arg namespace], and [emph not] fully qualified. +Returns a list containing the names of all variables in the specified +[arg namespace] and its children. The names are all given relative to +[arg namespace], and [emph not] fully qualified. + +[call [cmd {::namespacex normalize}] [arg namespace]] + +Returns the absolute name of [arg namespace], which is resolved +relative to the namespace of the caller, with all unneeded colon +characters removed. [call [cmd {::namespacex info vars}] [arg namespace] [opt [arg pattern]]] -This command returns a list containing the names of all variables in +Returns a list containing the names of all variables in the specified [arg namespace]. + +If the [arg pattern] argument is specified, then only variables +matching [arg pattern] are returned. Matching is determined using the +same rules as for [cmd {string match}]. [call [cmd {::namespacex state get}] [arg namespace]] -This command returns a dictionary holding the names and values of all -variables in the specified [arg namespace] and its child namespaces. +Returns a dictionary holding the names and values of all variables in +the specified [arg namespace] and its child namespaces. -[para] -Note that the names are all relative to [arg namespace], -and [emph not] fully qualified. +[para] Note that the names are all relative to [arg namespace], and +[emph not] fully qualified. [call [cmd {::namespacex state set}] [arg namespace] [arg dict]] -This command takes a dictionary holding the names and values for a set -of variables and replaces the current state of the specified -[arg namespace] and its child namespaces with this state. +Takes a dictionary holding the names and values for a set of variables +and replaces the current state of the specified [arg namespace] and +its child namespaces with this state. The result of the command is the empty string. [call [cmd {::namespacex state drop}] [arg namespace]] -This command unsets all variables in the specified [arg namespace] and -its child namespaces. +Unsets all variables in the specified [arg namespace] and its child +namespaces. The result of the command is the empty string. +[call [cmd {::namespacex strip}] [arg prefix] [arg namespaces]] + +Each item in [arg namespaces] must be the absolute normalized name of +a child namespace of namespace [arg prefix]. + +Returns the corresponding list of relative names of child namespaces. + [list_end] + +[vset CATEGORY namespacex] +[include ../doctools2base/include/feedback.inc] [manpage_end] Index: modules/namespacex/namespacex.tcl ================================================================== --- modules/namespacex/namespacex.tcl +++ modules/namespacex/namespacex.tcl @@ -11,13 +11,22 @@ # # ## ### ##### ######## ############# ###################### ## Requisites package require Tcl 8.5 ; # namespace ensembles, {*} + +# The try command is used in the namespacex::import command. For +# backward compatibility we will use the try package from tcllib if +# running on a platform that does not have it as a core command, +# i.e. before 8.6. + +if {![llength [info commands try]]} { + package require try ; # tcllib +} namespace eval ::namespacex { - namespace export add hook info state + namespace export add hook info import normalize strip state namespace ensemble create namespace eval hook { namespace export add proc on next namespace ensemble create @@ -180,41 +189,88 @@ } } # # ## ### ##### ######## ############# ###################### ## Implementation :: Info - Visible API + +proc ::namespacex::import {from args} { + set upns [uplevel 1 {::namespace current}] + if {![string match ::* $from]} { + set from ${upns}::$from[set from {}] + } + set orig [namespace eval $from {::namespace export}] + try { + namespace eval $from {::namespace export *} + set tmp [::namespace current]::[::info cmdcount] + namespace eval $tmp [list ::namespace import ${from}::*] + if {[llength $args] == 1} { + lappend args [lindex $args 0] + } + dict size $args + foreach {old new} $args { + rename ${tmp}::$old ${upns}::$new + } + namespace delete $tmp + } finally { + namespace eval $from [list ::namespace export -clear {*}$orig] + } + return +} proc ::namespacex::info::allvars {ns} { - if {![string match {::*} $ns]} { set ns ::$ns } + set ns [uplevel 1 [list [namespace parent] normalize $ns]] ::set result [::info vars ${ns}::*] foreach cns [allchildren $ns] { lappend result {*}[::info vars ${cns}::*] } - return [Strip $ns $result] + return [::namespacex::Strip $ns $result] } proc ::namespacex::info::allchildren {ns} { - if {![string match {::*} $ns]} { set ns ::$ns } + set ns [uplevel 1 [list [namespace parent] normalize $ns]] ::set result [list] foreach cns [::namespace children $ns] { lappend result {*}[allchildren $cns] lappend result $cns } return $result } proc ::namespacex::info::vars {ns {pattern *}} { - return [Strip $ns [::info vars ${ns}::$pattern]] + set ns [uplevel 1 [list [namespace parent] normalize $ns]] + return [::namespacex::Strip $ns [::info vars ${ns}::$pattern]] +} + +# this implementation avoids string operations +proc ::namespacex::normalize {ns} { + if {[uplevel 1 [list ::namespace exists $ns]]} { + return [uplevel 1 [list namespace eval $ns {::namespace current}]] + } + if {![string match ::* $ns]} { + set ns [uplevel 1 {::namespace current}]::$ns + } + regsub {::+} $ns :: ns + return $ns +} + +proc ::namespacex::strip {ns itemlist} { + set ns [uplevel 1 [list [namespace current] normalize $ns]] + set n [string length $ns] + incr n -1 + foreach i $itemlist { + if {[string range $i 0 $n] eq "$ns"} continue + return -code error "Expected $ns as prefix for $i, not found" + } + return [Strip $ns $itemlist] } -proc ::namespacex::info::Strip {ns itemlist} { +proc ::namespacex::Strip {ns itemlist} { + # Assert: is-fqn (ns) + if {![string match {::*} $ns]} { error "Expected fqn for ns" } + set n [string length $ns] - if {![string match {::*} $ns]} { - incr n 4 - } else { - incr n 2 - } + incr n 2 set result {} foreach i $itemlist { lappend result [string range $i $n end] } @@ -223,32 +279,32 @@ # # ## ### ##### ######## ############# ###################### ## Implementation :: State - Visible API proc ::namespacex::state::drop {ns} { - if {![string match {::*} $ns]} { ::set ns ::$ns } + ::set ns [uplevel 1 [list [namespace parent] normalize $ns]] namespace eval $ns [list ::unset {*}[::namespacex info allvars $ns]] return } proc ::namespacex::state::get {ns} { - if {![string match {::*} $ns]} { ::set ns ::$ns } + ::set ns [uplevel 1 [list [namespace parent] normalize $ns]] ::set result {} foreach v [::namespacex info allvars $ns] { namespace upvar $ns $v value lappend result $v $value } return $result } proc ::namespacex::state::set {ns state} { - if {![string match {::*} $ns]} { ::set ns ::$ns } + ::set ns [uplevel 1 [list [namespace parent] normalize $ns]] # Inlined 'state drop'. namespace eval $ns [list ::unset {*}[::namespacex info allvars $ns]] namespace eval $ns [list variable {*}$state] return } # # ## ### ##### ######## ############# ###################### ## Ready -package provide namespacex 0.1 +package provide namespacex 0.2 Index: modules/namespacex/namespacex.test ================================================================== --- modules/namespacex/namespacex.test +++ modules/namespacex/namespacex.test @@ -13,294 +13,585 @@ testing { useLocal namespacex.tcl namespacex } # ------------------------------------------------------------------------- +## helpers -proc ns_setup {} { - namespace eval ::X { +proc ns_setup {{parent {}}} { + namespace eval ${parent}::X { namespace eval A {} namespace eval B { namespace eval D {} } namespace eval C {} } } -proc ns2_setup {} { - namespace eval ::X { +proc ns2_setup {{parent {}}} { + namespace eval ${parent}::X { variable vXa 1 variable vXb aleph namespace eval B { variable vB 3 } } } -proc ns3_setup {} { - namespace eval ::X { +proc ns3_setup {{parent {}}} { + namespace eval ${parent}::X { namespace eval B { variable vB mjolnir } } } + +if {[package vsatisfies [package present Tcl] 8.6]} { + # 8.6+ args => ?arg ...? + proc E {text} { string map [list "..." "?arg ...?"] $text } +} else { + # 8.5- args => ... + proc E {text} { set text } +} + +# ------------------------------------------------------------------------- +## hook add + +test namespacex-hook-add-1.0 { + namespacex hook add: add a single hook +} -setup { + variable hadd1 20 + + proc h {args} { + variable hadd1 + set hadd1 40 + return + } + namespace eval ::testHook { + proc testProc {} { + foo a b c + } + } +} -cleanup { + namespace delete ::testHook + rename h {} +} -body { + namespacex hook add ::testHook [namespace code h] + ::testHook::testProc + return $hadd1 +} -result {40} + +# ------------------------------------------------------------------------- +## normalize + +test namespacex-normalize-1.0 {namespacex normalize, wrong\#args, not enough} -body { + namespacex normalize +} -returnCodes error -result {wrong # args: should be "namespacex normalize ns"} + +test namespacex-normalize-1.1 {namespacex normalize, wrong\#args, too many} -body { + namespacex normalize N X +} -returnCodes error -result {wrong # args: should be "namespacex normalize ns"} + +test namespacex-normalize-2.0.0 {namespacex normalize, fqn} -body { + namespacex normalize ::X +} -result {::X} + +test namespacex-normalize-2.0.1 {namespacex normalize, relative to global} -body { + namespacex normalize X +} -result {::X} + +test namespacex-normalize-2.0.2 {namespacex normalize, relative to non-global} -body { + namespace eval ::Q { + namespacex normalize X + } +} -cleanup { + namespace delete ::Q +} -result {::Q::X} + +# ------------------------------------------------------------------------- +## strip + +test namespacex-strip-1.0 {namespacex strip, wrong\#args, not enough} -body { + namespacex strip +} -returnCodes error -result {wrong # args: should be "namespacex strip ns itemlist"} + +test namespacex-strip-1.1 {namespacex strip, wrong\#args, not enough} -body { + namespacex strip N +} -returnCodes error -result {wrong # args: should be "namespacex strip ns itemlist"} + +test namespacex-strip-1.2 {namespacex strip, wrong\#args, too many} -body { + namespacex strip N I X +} -returnCodes error -result {wrong # args: should be "namespacex strip ns itemlist"} + +test namespacex-strip-2.0 {namespacex strip, bad child, relative} -body { + namespacex strip ::X {Q} +} -returnCodes error -result {Expected ::X as prefix for Q, not found} + +test namespacex-strip-2.1 {namespacex strip, bad child, absolute} -body { + namespacex strip ::X {::Q} +} -returnCodes error -result {Expected ::X as prefix for ::Q, not found} + +test namespacex-strip-2.1 {namespacex strip, proper children} -body { + namespacex strip ::X {::X ::X::Q} +} -result {{} Q} + +# ------------------------------------------------------------------------- +## import + +test namespacex-import-1.0 {namespacex import, wrong\#args, not enough} -body { + namespacex import +} -returnCodes error -result [E {wrong # args: should be "namespacex import from ..."}] + +test namespacex-import-2.0 { + namespacex import from a child namespace +} -setup { + namespace eval importTest { + proc t {} { + return [namespace current] + } + } +} -cleanup { + namespace delete importTest +} -body { + namespacex import importTest t + t +} -result ::importTest + +test namespacex-import-2.1 { + namespacex import from fully qualified namespace +} -setup { + namespace eval ::importTest { + proc t {} { + return [namespace current] + } + } +} -cleanup { + namespace delete ::importTest +} -body { + namespacex import ::importTest t + t +} -result {::importTest} + +test namespacex-import-2.2 { + namespacex import multiple commands +} -setup { + namespace eval ::importTest { + proc a {} { + return "a: [namespace current]" + } + proc b {} { + return "b: [namespace current]" + } + } +} -cleanup { + namespace delete ::importTest +} -body { + namespacex import ::importTest a myA b myB + append result [myA] " " [myB] + return $result +} -result {a: ::importTest b: ::importTest} # ------------------------------------------------------------------------- +## info allchildren -test namespacex-info-allchildren-1.0 {namespacex info allchildren, wrong\#args} -body { +test namespacex-info-allchildren-1.0 {namespacex info allchildren, wrong\#args, not enough} -body { namespacex info allchildren } -returnCodes error -result {wrong # args: should be "namespacex info allchildren ns"} -test namespacex-info-allchildren-1.1 {namespacex info allchildren, wrong\#args} -body { +test namespacex-info-allchildren-1.1 {namespacex info allchildren, wrong\#args, too many} -body { namespacex info allchildren N X } -returnCodes error -result {wrong # args: should be "namespacex info allchildren ns"} -test namespacex-info-allchildren-2.0.0 {namespacex info allchildren} -setup { +test namespacex-info-allchildren-2.0.0 {namespacex info allchildren, fqn} -setup { ns_setup } -body { lsort -dict [namespacex info allchildren ::X] } -cleanup { namespace delete ::X } -result {::X::A ::X::B ::X::B::D ::X::C} -test namespacex-info-allchildren-2.0.1 {namespacex info allchildren} -setup { +test namespacex-info-allchildren-2.0.1 {namespacex info allchildren, relative to global} -setup { ns_setup } -body { lsort -dict [namespacex info allchildren X] } -cleanup { namespace delete ::X } -result {::X::A ::X::B ::X::B::D ::X::C} + +test namespacex-info-allchildren-2.0.2 {namespacex info allchildren, relative to non-global} -setup { + ns_setup ::Q +} -body { + namespace eval ::Q { + lsort -dict [namespacex info allchildren X] + } +} -cleanup { + namespace delete ::Q +} -result {::Q::X::A ::Q::X::B ::Q::X::B::D ::Q::X::C} # ------------------------------------------------------------------------- +## info vars -test namespacex-info-vars-1.0 {namespacex info vars, wrong\#args} -body { +test namespacex-info-vars-1.0 {namespacex info vars, wrong\#args, not enough} -body { namespacex info vars } -returnCodes error -result {wrong # args: should be "namespacex info vars ns ?pattern?"} -test namespacex-info-vars-1.1 {namespacex info vars, wrong\#args} -body { +test namespacex-info-vars-1.1 {namespacex info vars, wrong\#args, too many} -body { namespacex info vars N P X } -returnCodes error -result {wrong # args: should be "namespacex info vars ns ?pattern?"} -test namespacex-info-vars-2.0 {namespacex info vars} -setup { +test namespacex-info-vars-2.0.0 {namespacex info vars, fqn} -setup { ns2_setup } -body { lsort -dict [namespacex info vars ::X] } -cleanup { namespace delete ::X } -result {vXa vXb} + +test namespacex-info-vars-2.0.1 {namespacex info vars, relative to global} -setup { + ns2_setup +} -body { + lsort -dict [namespacex info vars X] +} -cleanup { + namespace delete ::X +} -result {vXa vXb} + +test namespacex-info-vars-2.0.2 {namespacex info vars, relative to non-global} -setup { + ns2_setup ::Q +} -body { + namespace eval ::Q { + lsort -dict [namespacex info vars X] + } +} -cleanup { + namespace delete ::Q +} -result {vXa vXb} test namespacex-info-vars-2.1 {namespacex info vars} -setup { namespace eval ::X {} } -body { lsort -dict [namespacex info vars ::X] } -cleanup { namespace delete ::X } -result {} -test namespacex-info-vars-2.2 {namespacex info vars} -setup { +test namespacex-info-vars-2.2.0 {namespacex info vars, fqn} -setup { ns3_setup } -body { lsort -dict [namespacex info vars ::X] } -cleanup { namespace delete ::X } -result {} + +test namespacex-info-vars-2.2.1 {namespacex info vars, relative to global} -setup { + ns3_setup +} -body { + lsort -dict [namespacex info vars X] +} -cleanup { + namespace delete ::X +} -result {} + +test namespacex-info-vars-2.2.2 {namespacex info vars, relative to non-global} -setup { + ns3_setup ::Q +} -body { + namespace eval ::Q { + lsort -dict [namespacex info vars X] + } +} -cleanup { + namespace delete ::Q +} -result {} # ------------------------------------------------------------------------- +## info allvars -test namespacex-info-allvars-1.0 {namespacex info allvars, wrong\#args} -body { +test namespacex-info-allvars-1.0 {namespacex info allvars, wrong\#args, not enough} -body { namespacex info allvars } -returnCodes error -result {wrong # args: should be "namespacex info allvars ns"} -test namespacex-info-allvars-1.1 {namespacex info allvars, wrong\#args} -body { +test namespacex-info-allvars-1.1 {namespacex info allvars, wrong\#args, too many} -body { namespacex info allvars N X } -returnCodes error -result {wrong # args: should be "namespacex info allvars ns"} -test namespacex-info-allvars-2.0.0 {namespacex info allvars} -setup { +test namespacex-info-allvars-2.0.0 {namespacex info allvars, fqn} -setup { ns2_setup } -body { lsort -dict [namespacex info allvars ::X] } -cleanup { namespace delete ::X } -result {B::vB vXa vXb} -test namespacex-info-allvars-2.0.1 {namespacex info allvars} -setup { +test namespacex-info-allvars-2.0.1 {namespacex info allvars, relative to global} -setup { ns2_setup } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete ::X } -result {B::vB vXa vXb} -test namespacex-info-allvars-2.1.0 {namespacex info allvars} -setup { +test namespacex-info-allvars-2.0.2 {namespacex info allvars, relative to non-global} -setup { + ns2_setup ::Q +} -body { + namespace eval ::Q { + lsort -dict [namespacex info allvars X] + } +} -cleanup { + namespace delete ::Q +} -result {B::vB vXa vXb} + +test namespacex-info-allvars-2.1.0 {namespacex info allvars, fqn} -setup { namespace eval ::X {} } -body { lsort -dict [namespacex info allvars ::X] } -cleanup { namespace delete ::X } -result {} -test namespacex-info-allvars-2.1.1 {namespacex info allvars} -setup { +test namespacex-info-allvars-2.1.1 {namespacex info allvars, relative to global} -setup { namespace eval ::X {} } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete ::X } -result {} -test namespacex-info-allvars-2.2.0 {namespacex info allvars} -setup { +test namespacex-info-allvars-2.1.2 {namespacex info allvars, relative to non-global} -setup { + namespace eval ::Q::X {} +} -body { + namespace eval ::Q { + lsort -dict [namespacex info allvars X] + } +} -cleanup { + namespace delete ::Q +} -result {} + +test namespacex-info-allvars-2.2.0 {namespacex info allvars, fqn} -setup { ns3_setup } -body { lsort -dict [namespacex info allvars ::X] } -cleanup { namespace delete ::X } -result {B::vB} -test namespacex-info-allvars-2.2.1 {namespacex info allvars} -setup { +test namespacex-info-allvars-2.2.1 {namespacex info allvars, relative to global} -setup { ns3_setup } -body { lsort -dict [namespacex info allvars X] } -cleanup { namespace delete ::X } -result {B::vB} + +test namespacex-info-allvars-2.2.2 {namespacex info allvars, relative to non-global} -setup { + ns3_setup ::Q +} -body { + namespace eval ::Q { + lsort -dict [namespacex info allvars X] + } +} -cleanup { + namespace delete ::Q +} -result {B::vB} # ------------------------------------------------------------------------- +## state get -test namespacex-state-get-1.0 {namespacex state get, wrong\#args} -body { +test namespacex-state-get-1.0 {namespacex state get, wrong\#args, not enough} -body { namespacex state get } -returnCodes error -result {wrong # args: should be "namespacex state get ns"} -test namespacex-state-get-1.1 {namespacex state get, wrong\#args} -body { +test namespacex-state-get-1.1 {namespacex state get, wrong\#args, too many} -body { namespacex state get N X } -returnCodes error -result {wrong # args: should be "namespacex state get ns"} -test namespacex-state-get-2.0.0 {namespacex state get} -setup { - ns2_setup -} -body { - dictsort [namespacex state get ::X] -} -cleanup { - namespace delete ::X -} -result {B::vB 3 vXa 1 vXb aleph} - -test namespacex-state-get-2.0.1 {namespacex state get} -setup { - ns2_setup -} -body { - dictsort [namespacex state get X] -} -cleanup { - namespace delete ::X -} -result {B::vB 3 vXa 1 vXb aleph} - -test namespacex-state-get-2.1.0 {namespacex state get} -setup { +test namespacex-state-get-2.0.0 {namespacex state get, fqn} -setup { + ns2_setup +} -body { + dictsort [namespacex state get ::X] +} -cleanup { + namespace delete ::X +} -result {B::vB 3 vXa 1 vXb aleph} + +test namespacex-state-get-2.0.1 {namespacex state get, relative to global} -setup { + ns2_setup +} -body { + dictsort [namespacex state get X] +} -cleanup { + namespace delete ::X +} -result {B::vB 3 vXa 1 vXb aleph} + +test namespacex-state-get-2.0.2 {namespacex state get, relative to non-global} -setup { + ns2_setup ::Q +} -body { + namespace eval ::Q { + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {B::vB 3 vXa 1 vXb aleph} + +test namespacex-state-get-2.1.0 {namespacex state get, fqn} -setup { namespace eval ::X {} } -body { dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-get-2.1.1 {namespacex state get} -setup { +test namespacex-state-get-2.1.1 {namespacex state get, relative to global} -setup { namespace eval ::X {} } -body { dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-get-2.2.0 {namespacex state get} -setup { +test namespacex-state-get-2.1.2 {namespacex state get, relative to non-global} -setup { + namespace eval ::Q::X {} +} -body { + namespace eval ::Q { + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {} + +test namespacex-state-get-2.2.0 {namespacex state get, fqn} -setup { ns3_setup } -body { dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {B::vB mjolnir} -test namespacex-state-get-2.2.1 {namespacex state get} -setup { +test namespacex-state-get-2.2.1 {namespacex state get, relative to global} -setup { ns3_setup } -body { dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {B::vB mjolnir} + +test namespacex-state-get-2.2.2 {namespacex state get, relative to non-global} -setup { + ns3_setup ::Q +} -body { + namespace eval ::Q { + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {B::vB mjolnir} # ------------------------------------------------------------------------- +## state drop -test namespacex-state-drop-1.0 {namespacex state drop, wrong\#args} -body { +test namespacex-state-drop-1.0 {namespacex state drop, wrong\#args, not enough} -body { namespacex state drop } -returnCodes error -result {wrong # args: should be "namespacex state drop ns"} -test namespacex-state-drop-1.1 {namespacex state drop, wrong\#args} -body { +test namespacex-state-drop-1.1 {namespacex state drop, wrong\#args, too many} -body { namespacex state drop N X } -returnCodes error -result {wrong # args: should be "namespacex state drop ns"} -test namespacex-state-drop-2.0.0 {namespacex state drop} -setup { +test namespacex-state-drop-2.0.0 {namespacex state drop, fqn} -setup { ns2_setup } -body { namespacex state drop ::X dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-drop-2.0.1 {namespacex state drop} -setup { +test namespacex-state-drop-2.0.1 {namespacex state drop, relative to global} -setup { ns2_setup } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-drop-2.1.0 {namespacex state drop} -setup { +test namespacex-state-drop-2.0.2 {namespacex state drop, relative to non-global} -setup { + ns2_setup ::Q +} -body { + namespace eval ::Q { + namespacex state drop X + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {} + +test namespacex-state-drop-2.1.0 {namespacex state drop, fqn} -setup { namespace eval ::X {} } -body { namespacex state drop X dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-drop-2.1.1 {namespacex state drop} -setup { +test namespacex-state-drop-2.1.1 {namespacex state drop, relative to global} -setup { namespace eval ::X {} } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-drop-2.2.0 {namespacex state drop} -setup { +test namespacex-state-drop-2.1.2 {namespacex state drop, relative to non-global} -setup { + namespace eval ::Q::X {} +} -body { + namespace eval ::Q { + namespacex state drop X + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {} + +test namespacex-state-drop-2.2.0 {namespacex state drop, fqn} -setup { ns3_setup } -body { namespacex state drop X dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {} -test namespacex-state-drop-2.2.1 {namespacex state drop} -setup { +test namespacex-state-drop-2.2.1 {namespacex state drop, relative to global} -setup { ns3_setup } -body { namespacex state drop X dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {} + +test namespacex-state-drop-2.2.2 {namespacex state drop, relative to non-global} -setup { + ns3_setup ::Q +} -body { + namespace eval ::Q { + namespacex state drop X + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {} # ------------------------------------------------------------------------- +## state set -test namespacex-state-set-1.0 {namespacex state set, wrong\#args} -body { +test namespacex-state-set-1.0 {namespacex state set, wrong\#args, not enough} -body { namespacex state set } -returnCodes error -result {wrong # args: should be "namespacex state set ns state"} -test namespacex-state-set-1.1 {namespacex state set, wrong\#args} -body { +test namespacex-state-set-1.1 {namespacex state set, wrong\#args, not enough} -body { namespacex state set N } -returnCodes error -result {wrong # args: should be "namespacex state set ns state"} -test namespacex-state-set-1.2 {namespacex state set, wrong\#args} -body { +test namespacex-state-set-1.2 {namespacex state set, wrong\#args, too many} -body { namespacex state set N S X } -returnCodes error -result {wrong # args: should be "namespacex state set ns state"} -test namespacex-state-set-2.0.0 {namespacex state set} -setup { +test namespacex-state-set-2.0.0 {namespacex state set, fqn} -setup { ns2_setup set ST [namespacex state get ::X] ns3_setup } -body { namespacex state set ::X $ST @@ -307,11 +598,11 @@ dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {B::vB 3 vXa 1 vXb aleph} -test namespacex-state-set-2.0.1 {namespacex state set} -setup { +test namespacex-state-set-2.0.1 {namespacex state set, relative to global} -setup { ns2_setup set ST [namespacex state get ::X] ns3_setup } -body { namespacex state set X $ST @@ -318,11 +609,25 @@ dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {B::vB 3 vXa 1 vXb aleph} -test namespacex-state-set-2.1.0 {namespacex state set} -setup { +test namespacex-state-set-2.0.1 {namespacex state set, relative to non-global} -setup { + ns2_setup + set ST [namespacex state get ::X] + namespace delete ::X + ns3_setup ::Q +} -body { + namespace eval ::Q { + namespacex state set X $ST + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {B::vB 3 vXa 1 vXb aleph} + +test namespacex-state-set-2.1.0 {namespacex state set, fqn} -setup { ns3_setup set ST [namespacex state get ::X] ns2_setup } -body { namespacex state set ::X $ST @@ -329,11 +634,11 @@ dictsort [namespacex state get ::X] } -cleanup { namespace delete ::X } -result {B::vB mjolnir} -test namespacex-state-set-2.1.1 {namespacex state set} -setup { +test namespacex-state-set-2.1.1 {namespacex state set, relative to global} -setup { ns3_setup set ST [namespacex state get ::X] ns2_setup } -body { namespacex state set X $ST @@ -340,12 +645,27 @@ dictsort [namespacex state get X] } -cleanup { namespace delete ::X } -result {B::vB mjolnir} +test namespacex-state-set-2.1.2 {namespacex state set, relative to non-global} -setup { + ns3_setup + set ST [namespacex state get ::X] + namespace delete ::X + ns2_setup ::Q +} -body { + namespace eval ::Q { + namespacex state set X $ST + dictsort [namespacex state get X] + } +} -cleanup { + namespace delete ::Q +} -result {B::vB mjolnir} + +## done # ------------------------------------------------------------------------- testsuiteCleanup # Local variables: # mode: tcl # indent-tabs-mode: nil # End: Index: modules/namespacex/pkgIndex.tcl ================================================================== --- modules/namespacex/pkgIndex.tcl +++ modules/namespacex/pkgIndex.tcl @@ -1,5 +1,5 @@ if {![package vsatisfies [package provide Tcl] 8.5]} { # PRAGMA: returnok return } -package ifneeded namespacex 0.1 [list source [file join $dir namespacex.tcl]] +package ifneeded namespacex 0.2 [list source [file join $dir namespacex.tcl]]