我可以添加到:: oo :: define来添加全局tclOO类定义扩展,我该如何非全局地执行此操作?

时间:2012-12-03 19:57:29

标签: 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 redis-server
  ...
}

然后可以将它们用作

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

1 个答案:

答案 0 :(得分:1)

虽然您无法直接在oo::define系统中制作特定于类的扩展命令,但您可以非常轻松地完成下一个最佳操作。诀窍是在定义处理期间使用namespace path对命名空间的附加命令进行概要分析。这有点过于花哨的说法,在元类构造函数中很容易做到这一点:

# 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,那么module定义可以更简单(这次没有注释):

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]
        }
    }
}

原则上它是相同的,但使用8.6的try / finally命令。