I'm building a Smalltalk API to an XML-based web service. 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.
This works great, but passing a giant string to #compile:
just feels really wrong to me; 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. E.g.:
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?
If you just want the source string to more clearly reflect the method:
If you want the source to be syntax-checked, you could start with a template method like this:
And then fill the template accordingly, like:
Of course, all of this would be clearer if some methods were extracted :)
Well, compile: takes a String. If you want something more typesafe, you could build a parsetree and use that.
Suppose you have template method:
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.
I would use block:
You can still make himaker a method