[英]How can I add methods to a class at runtime in Smalltalk?
I'm building a Smalltalk API to an XML-based web service. 我正在为基于XML的Web服务构建Smalltalk API。 The XML service is so regular that, rather than write the methods by hand, I figured I'd just override #doesNotUnderstand:
to dynamically add methods via MyApi class>>compile:
, then call all the methods once in a workspace, then remove the DNU and have my nice API. XML服务非常规则,而不是手工编写方法,我想我只是覆盖#doesNotUnderstand:
通过MyApi class>>compile:
动态添加方法MyApi class>>compile:
,然后在工作区中调用所有方法一次,然后删除DNU并拥有我不错的API。
This works great, but passing a giant string to #compile:
just feels really wrong to me; 这很好用,但将一根巨大的字符串传递给#compile:
对我来说感觉真的很不对劲; in Python and other languages, I'd be able to attach a nicely syntax-checked lambda to a class to achieve a similar effect in a safer manner. 在Python和其他语言中,我能够将一个很好的语法检查的lambda附加到一个类,以更安全的方式实现类似的效果。 Eg: 例如:
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)
versus 与
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
Surely there must be something as clean as the Python version? 当然必须有像Python版本一样干净的东西?
If you just want the source string to more clearly reflect the method: 如果您只是希望源字符串更清楚地反映该方法:
SomeObject>>addHello: name
| methodTemplate methodSource |
methodTemplate := 'sayHello{1}Times: count
count timesRepeat: [ Transcript show: ''Hi, {1}!'' ].'.
methodSource := methodTemplate format: { name }.
self class compile: methodSource.
If you want the source to be syntax-checked, you could start with a template method like this: 如果您希望对源进行语法检查,可以从这样的模板方法开始:
sayHelloTemplate: count
count timesRepeat: [ Transcript show: 'Hi, NAME' ].
And then fill the template accordingly, like: 然后相应地填写模板,例如:
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.
Of course, all of this would be clearer if some methods were extracted :) 当然,如果提取了一些方法,所有这些都会更清楚:)
Suppose you have template method: 假设你有模板方法:
SomeClass>>himaker: aName
Transcript show: 'Hi ...'
Then you can copy it to other class, just don't forget to set selector and class if you don't want to confuse the system browser. 然后你可以将它复制到其他类,如果你不想混淆系统浏览器,不要忘记设置选择器和类。 Or if you don't care, that just install the copy at method dictionary. 或者,如果您不在乎,只需在方法词典中安装副本即可。
| 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.
Well, compile: takes a String. 好吧,编译:接受一个字符串。 If you want something more typesafe, you could build a parsetree and use that. 如果你想要更安全的东西,你可以构建一个parsetree并使用它。
I would use block: 我会用块:
himaker := [:name | [:n | n timesRepeat: [Transcript show: 'Hi , ', name, '!']]]
hibob = himaker value: 'bob'.
hialice = himaker value: 'alice'.
hialice value: 2
You can still make himaker a method 你仍然可以使himaker成为一种方法
himaker: name
^[:n | n timesRepeat: [Transcript show: 'Hi, ', name, '!']]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.