How can I add methods to a class at runtime in Smalltalk?

后端 未结 4 465
长情又很酷
长情又很酷 2020-12-29 14:44

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 #doe

相关标签:
4条回答
  • 2020-12-29 15:08

    Well, compile: takes a String. If you want something more typesafe, you could build a parsetree and use that.

    0 讨论(0)
  • 2020-12-29 15:10

    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: name
        ^[:n | n timesRepeat: [Transcript show: 'Hi, ', name, '!']]
    
    0 讨论(0)
  • 2020-12-29 15:20

    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 :)

    0 讨论(0)
  • 2020-12-29 15:27

    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.
    
    0 讨论(0)
提交回复
热议问题