summaryrefslogtreecommitdiffstats
path: root/generic/tclOOScript.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclOOScript.tcl')
-rw-r--r--generic/tclOOScript.tcl188
1 files changed, 122 insertions, 66 deletions
diff --git a/generic/tclOOScript.tcl b/generic/tclOOScript.tcl
index e0af23f..c0b4d1f 100644
--- a/generic/tclOOScript.tcl
+++ b/generic/tclOOScript.tcl
@@ -11,74 +11,103 @@
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
-::proc ::oo::Helpers::callback {method args} {
- list [uplevel 1 {namespace which my}] $method {*}$args
-}
+::namespace eval ::oo::Helpers {
+ ::namespace path {}
-::proc ::oo::Helpers::mymethod {method args} {
- list [uplevel 1 {namespace which my}] $method {*}$args
-}
+ proc callback {method args} {
+ list [uplevel 1 {::namespace which my}] $method {*}$args
+ }
-::proc ::oo::Helpers::classvariable {name args} {
- # Get a reference to the class's namespace
- set ns [info object namespace [uplevel 1 {self class}]]
- # Double up the list of variable names
- foreach v [list $name {*}$args] {
- if {[string match *(*) $v]} {
- return -code error [string cat {bad variable name "} $v {": can't create a scalar variable that looks like an array element}]
- }
- if {[string match *::* $v]} {
- return -code error [string cat {bad variable name "} $v {": can't create a local variable with a namespace separator in it}]
- }
- lappend vs $v $v
+ proc mymethod {method args} {
+ list [uplevel 1 {::namespace which my}] $method {*}$args
}
- # Lastly, link the caller's local variables to the class's variables
- tailcall namespace upvar $ns {*}$vs
-}
-::proc ::oo::Helpers::link {args} {
- set ns [uplevel 1 {namespace current}]
- foreach link $args {
- if {[llength $link] == 2} {
- lassign $link src dst
- } else {
- lassign $link src
- set dst $src
- }
- if {![string match ::* $src]} {
- set src [string cat $ns :: $src]
- }
- interp alias {} $src {} ${ns}::my $dst
- trace add command ${ns}::my delete [list ::oo::Helpers::Unlink $src]
+ proc classvariable {name args} {
+ # Get a reference to the class's namespace
+ set ns [info object namespace [uplevel 1 {self class}]]
+ # Double up the list of variable names
+ foreach v [list $name {*}$args] {
+ if {[string match *(*) $v]} {
+ variable
+ return -code error [format \
+ {bad variable name "%s": can't create a scalar variable that looks like an array element} \
+ $v]
+ }
+ if {[string match *::* $v]} {
+ return -code error [format \
+ {bad variable name "%s": can't create a local variable with a namespace separator in it} \
+ $v]
+ }
+ lappend vs $v $v
+ }
+ # Lastly, link the caller's local variables to the class's variables
+ tailcall namespace upvar $ns {*}$vs
}
- return
-}
-::proc ::oo::Helpers::Unlink {cmd args} {
- if {[namespace which $cmd] ne {}} {
- rename $cmd {}
+
+ proc link {args} {
+ set ns [uplevel 1 {::namespace current}]
+ foreach link $args {
+ if {[llength $link] == 2} {
+ lassign $link src dst
+ } else {
+ lassign $link src
+ set dst $src
+ }
+ if {![string match ::* $src]} {
+ set src [string cat $ns :: $src]
+ }
+ interp alias {} $src {} ${ns}::my $dst
+ trace add command ${ns}::my delete [list \
+ ::oo::UnlinkLinkedCommand $src]
+ }
+ return
}
}
-::proc ::oo::DelegateName {class} {
- string cat [info object namespace $class] {:: oo ::delegate}
-}
+::namespace eval ::oo {
+ proc UnlinkLinkedCommand {cmd args} {
+ if {[namespace which $cmd] ne {}} {
+ rename $cmd {}
+ }
+ }
-proc ::oo::MixinClassDelegates {class} {
- if {![info object isa class $class]} {
- return
+ proc DelegateName {class} {
+ string cat [info object namespace $class] {:: oo ::delegate}
}
- set delegate [::oo::DelegateName $class]
- if {![info object isa class $delegate]} {
- return
+
+ proc MixinClassDelegates {class} {
+ if {![info object isa class $class]} {
+ return
+ }
+ set delegate [DelegateName $class]
+ if {![info object isa class $delegate]} {
+ return
+ }
+ foreach c [info class superclass $class] {
+ set d [DelegateName $c]
+ if {![info object isa class $d]} {
+ continue
+ }
+ define $delegate superclass -append $d
+ }
+ objdefine $class mixin -append $delegate
}
- foreach c [info class superclass $class] {
- set d [::oo::DelegateName $c]
- if {![info object isa class $d]} {
- continue
- }
- ::oo::define $delegate superclass -append $d
+
+ proc UpdateClassDelegatesAfterClone {originObject targetObject} {
+ # Rebuild the class inheritance delegation class
+ set originDelegate [DelegateName $originObject]
+ set targetDelegate [DelegateName $targetObject]
+ if {
+ [info object isa class $originDelegate]
+ && ![info object isa class $targetDelegate]
+ } then {
+ copy $originDelegate $targetDelegate
+ objdefine $targetObject mixin -set \
+ {*}[lmap c [info object mixin $targetObject] {
+ if {$c eq $originDelegate} {set targetDelegate} {set c}
+ }]
+ }
}
- ::oo::objdefine $class mixin -append $delegate
}
::namespace eval ::oo::define {
@@ -86,8 +115,9 @@ proc ::oo::MixinClassDelegates {class} {
# Create the method on the class if the caller gave arguments and body
::set argc [::llength [::info level 0]]
::if {$argc == 3} {
- ::return -code error [::string cat {wrong # args: should be "} \
- [::lindex [::info level 0] 0] { name ?args body?"}]
+ ::return -code error [::format \
+ {wrong # args: should be "%s name ?args body?"} \
+ [::lindex [::info level 0] 0]]
}
::set cls [::uplevel 1 self]
::if {$argc == 4} {
@@ -140,17 +170,43 @@ proc ::oo::MixinClassDelegates {class} {
::oo::objdefine ::oo::define::mixin forward --default-operation my -set
::oo::objdefine ::oo::objdefine::mixin forward --default-operation my -set
+::oo::define ::oo::object method <cloned> {originObject} {
+ # Copy over the procedures from the original namespace
+ foreach p [info procs [info object namespace $originObject]::*] {
+ set args [info args $p]
+ set idx -1
+ foreach a $args {
+ if {[info default $p $a d]} {
+ lset args [incr idx] [list $a $d]
+ } else {
+ lset args [incr idx] [list $a]
+ }
+ }
+ set b [info body $p]
+ set p [namespace tail $p]
+ proc $p $args $b
+ }
+ # Copy over the variables from the original namespace
+ foreach v [info vars [info object namespace $originObject]::*] {
+ upvar 0 $v vOrigin
+ namespace upvar [namespace current] [namespace tail $v] vNew
+ if {[info exists vOrigin]} {
+ if {[array exists vOrigin]} {
+ array set vNew [array get vOrigin]
+ } else {
+ set vNew $vOrigin
+ }
+ }
+ }
+ # General commands, sub-namespaces and advancd variable config (traces,
+ # etc) are *not* copied over. Classes that want that should do it
+ # themselves.
+}
+
::oo::define ::oo::class method <cloned> {originObject} {
next $originObject
# Rebuild the class inheritance delegation class
- set originDelegate [::oo::DelegateName $originObject]
- set targetDelegate [::oo::DelegateName [self]]
- if {[info object isa class $originDelegate] && ![info object isa class $targetDelegate]} {
- ::oo::copy $originDelegate $targetDelegate
- ::oo::objdefine [self] mixin -set {*}[lmap c [info object mixin [self]] {
- if {$c eq $originDelegate} {set targetDelegate} {set c}
- }]
- }
+ ::oo::UpdateClassDelegatesAfterClone $originObject [self]
}
::oo::class create ::oo::singleton {