proc oo::define::public { method args } {
set class [oo::_setup_helper]
switch -glob $method {
classvar {
foreach { name value } $args {
uplevel 1 [list classvar $name $value]
uplevel 1 [subst { public method $name args { set $name {*}\$args } }]
}
}
var* {
foreach { name value } $args {
uplevel 1 [list variable $name]
uplevel 1 [subst { public method $name args { set $name {*}\$args } }]
lappend [$class varname __variable] $name $value
}
}
method {
lassign $args name args body
uplevel 1 [list method $name $args $body]
uplevel 1 [list export $name]
}
proc {
lassign $args name args body
uplevel 1 [list proc $name $args $body]
uplevel 1 [list export $name]
}
}
}
proc oo::define::private { method args } {
set class [oo::_setup_helper]
switch -glob $method {
classvar {
foreach { name value } $args {
uplevel 1 [list classvar $name $value]
}
}
var* {
foreach { name value } $args {
uplevel 1 [list variable $name]
lappend [$class varname __variable] $name $value
}
}
method {
lassign $args name args body
uplevel 1 [list method $name $args $body]
uplevel 1 [list unexport $name]
}
proc {
lassign $args name args body
uplevel 1 [list proc $name $args $body]
uplevel 1 [list unexport $name]
}
}
}
proc oo::define::classvar { args } {
set class [oo::_setup_helper]
foreach { name value } $args {
uplevel 1 [list variable $name]
set [$class varname $name] $value
lappend [$class varname __classvar] $name
}
}
proc oo::define::linked { args } {
set class [lindex [info level -1] 1]
oo::define $class { self export varname }
if { [lindex $args 0] ne "method" } {
set method [lindex $args 2] ; # Skip over public / private
} else {
set method [lindex $args 1]
}
lappend [$class varname __linked] $method ; # remember linked methods
uplevel 1 $args
}
proc oo::define::proc { args } {
set class [lindex [info level -1] 1]
oo::define $class { self export varname }
lappend [$class varname __linked] [lindex $args 0] ; # remember linked methods
uplevel 1 [list method {*}$args]
}
proc oo::_classvar { class varname } {
[info object class $class] varname $varname
}
proc oo::_get_classvar { class varname } {
if { [info exists [oo::_classvar $class $varname]] } {
set [oo::_classvar $class $varname]
}
}
proc oo::_setup_helper {} {
set class [lindex [info level -2] 1]
if { "::__oo_class_helper" ni [info class mixins $class] } {
uplevel 2 {
self export varname
mixin -append __oo_class_helper
}
}
set class
}
oo::class create __oo_class_helper {
constructor { args } {
# Initialize the instance variables
#
foreach { name value } [oo::_get_classvar [self] __variable] {
set [namespace current]::$name $value
}
# Link the classvars
#
foreach var [oo::_get_classvar [self] __classvar] {
upvar [oo::_classvar [self] $var] [namespace current]::$var
}
# Create the linked procs
#
foreach link [oo::_get_classvar [self] __linked] {
proc [namespace current]::$link args [subst { tailcall my $link {*}\$args }]
}
catch { next {*}$args }
}
}Some testing:
source tcloo.tcl
oo::class create clazz {
public variable A 1
private variable B 2
private variable F 2
classvar C 3
public classvar D 4
private classvar E 5
public method get { name } {
set $name
}
private proc aproc { name } {
set $name
}
public method tryproc {} {
aproc B
}
constructor { args } {
set F 10
set G 11
}
}
set inst [clazz create instance]
proc is { A B } {
if { $A ne $B } {
puts "Fail \n$A\n$B"
exit 1
}
}
proc message { script } {
try {
uplevel $script
} on error message {
return $message
}
}
is [$inst A] 1
is [$inst get A] 1
is [$inst A 4] 4
is [$inst A] 4
is [$inst get B] 2
is [message { $inst B }] {unknown method "B": must be A, D, destroy, get or tryproc}
is [$inst get C] 3
is [$inst get D] 4
is [$inst D] 4
is [message { $inst E }] {unknown method "E": must be A, D, destroy, get or tryproc}
is [$inst get F] 10
is [$inst tryproc] 2
puts OK
