7

我正在为基于 XML 的 Web 服务构建 Smalltalk API。XML 服务是如此的有规律,以至于与其手动编写方法,我想我只需重写#doesNotUnderstand:以通过 动态添加方法MyApi class>>compile:,然后在工作区中调用所有方法一次,然后删除 DNU 并拥有我的漂亮 API。

这很好用,但是将一根巨大的字符串传递#compile:给我感觉真的很不对;在 Python 和其他语言中,我可以将一个经过语法检查的 lambda 附加到一个类,以更安全的方式实现类似的效果。例如:

def himaker(name):
    def hello(self, times):
        for x in xrange(times):
            print "Hi, %s!" % name
    return hello
class C(object): pass
C.bob = himaker('Bob')
C.jerry = himaker('Jerry')
a = C()
a.bob(5)

相对

SomeObject>>addHello: name
    | source methodName |
    methodName := 'sayHello', name, 'Times:'.
    source := String streamContents: [ :s |
         s nextPutAll: methodName, ' count'.
         s nextPut: Character cr.
         s nextPut: Character tab.
         s nextPutAll: 'count timesRepeat: [ Transcript show: ''Hi, ', name, '!'' ].' ]
    SomeObject class compile: source

肯定有像 Python 版本一样干净的东西吗?

4

4 回答 4

4

如果您只是希望源字符串更清楚地反映方法:

SomeObject>>addHello: name
  | methodTemplate methodSource |
  methodTemplate := 'sayHello{1}Times: count
  count timesRepeat: [ Transcript show: ''Hi, {1}!'' ].'.   
  methodSource := methodTemplate format: { name }.
  self class compile: methodSource.

如果你想对源代码进行语法检查,你可以从这样的模板方法开始:

sayHelloTemplate: count
    count timesRepeat: [ Transcript show: 'Hi, NAME' ].

然后相应地填写模板,例如:

addHello2: name
    | methodTemplate methodSource |
    methodTemplate := (self class compiledMethodAt: #sayHelloTemplate:) decompileWithTemps.
    methodTemplate selector: ('sayHello', name, 'Times:') asSymbol.
    methodSource := methodTemplate sourceText copyReplaceAll: 'NAME' with: name.
    self class compile: methodSource.

当然,如果提取一些方法,所有这些都会更清楚:)

于 2010-12-17T04:01:17.843 回答
4

假设您有模板方法:

SomeClass>>himaker: aName
  Transcript show: 'Hi ...'

然后你可以将它复制到其他类,如果你不想混淆系统浏览器,不要忘记设置选择器和类。或者,如果您不在乎,只需将副本安装在方法字典中即可。

| method |

method := (SomeClass>>#himaker:) copy.

method methodClass: OtherClass.
method selector: #boo: .
OtherClass methodDict at: #boo: put: method.

method := method copy.
method selector: #bar: .
method methodClass: OtherClass2.
OtherClass2 methodDict at: #bar: put: method.
于 2010-12-18T08:19:36.993 回答
0

好吧,compile: 接受一个字符串。如果你想要更安全的东西,你可以构建一个分析树并使用它。

于 2010-12-19T13:56:13.437 回答
0

我会使用块:

himaker := [:name | [:n | n timesRepeat: [Transcript show: 'Hi , ', name, '!']]]
hibob = himaker value: 'bob'.
hialice = himaker value: 'alice'.
hialice value: 2

你仍然可以让himaker成为一种方法

himaker: name
    ^[:n | n timesRepeat: [Transcript show: 'Hi, ', name, '!']]
于 2010-12-21T10:37:23.720 回答