Class 我可以添加到::oo::define以添加全局tclOO类定义扩展,如何在非全局的情况下执行此操作?

Class 我可以添加到::oo::define以添加全局tclOO类定义扩展,如何在非全局的情况下执行此操作?,class,tcl,Class,Tcl,我发现一些TclOO资源提到可以创建::oo::class的子类。您还可以使用::oo::object create创建裸对象,但不能从裸类迁移到真实类(即父类oo::object到父类oo::class) 我希望创建一个用于定义模块的DSL,它只创建类定义 module create mysql 5.5 { executable mysqld method post_install { ... } } module create redis 2.6 { executable re

我发现一些TclOO资源提到可以创建
::oo::class
的子类。您还可以使用
::oo::object create
创建裸对象,但不能从裸类迁移到真实类(即父类
oo::object
到父类
oo::class

我希望创建一个用于定义模块的DSL,它只创建类定义

module create mysql 5.5 {
  executable mysqld
  method post_install { ... }
}

module create redis 2.6 {
  executable redis-server
  ...
}
然后可以将其用作

set mod [mysql new]
$mod install
$mod post_install

虽然您不能直接在
oo::define
系统中生成特定于类的扩展命令,但您可以非常轻松地完成次优任务。诀窍是使用
名称空间路径
在定义处理期间将附加命令配置到名称空间。这是一种有点过于花哨的说法,可以说元类构造函数很容易做到这一点:

# First, build the definition of the extensions
namespace eval ::ModuleDefineExtensions {
    proc executable {program} {
        # I'm not quite sure how you want to handle this, but [uplevel] and
        # [info level] will reveal what you need.
        puts "define executable as $program here"
    }
}

# Now, the [module] metaclass
oo::class create module {
    superclass oo::class
    constructor {definitionScript} {
        # Save the old path
        set oldpath [namespace eval ::oo::define {namespace path}]

        # Set the new one
        namespace eval ::oo::define {namespace path ::ModuleDefineExtensions}

        # Now let the superclass constructor handle this, trapping errors
        catch {next $definitionScript} msg opt

        # Restore the old path
        namespace eval ::oo::define [list namespace path $oldpath]

        # Rethrow any errors
        return -options $opt $msg
    }
}
您可能需要更多的比特和片段(例如,定义通用方法的模块类的适当默认超类),但这些是常规的


如果您使用的是8.6,
模块
的定义可以更简单(这次没有注释):


原则上是一样的,但是使用了8.6的try/finally命令。

您不能将非类更改为类,也不能将非类更改为类,反之亦然(因为它们下面有不同的C结构),并且
oo::object
oo::class
本身有固定的关系-其他一切都取决于它们但除了这些强制执行的限制外,你还可以在很大程度上改变周围的情况。你可以做的一些事情可能是不明智的,但是如果你需要的话,选择是存在的…
oo::class create module {
    superclass oo::class
    constructor {definitionScript} {
        set oldpath [namespace eval ::oo::define {namespace path}]
        namespace eval ::oo::define {namespace path ::ModuleDefineExtensions}
        try {
            next $definitionScript
        } finally {
            namespace eval ::oo::define [list namespace path $oldpath]
        }
    }
}