views:

198

answers:

4

I have a class and I want to change the name of a specific method in run time. I guess there's a method in the 'Behavior' class that does it. But I just can't find it. any help? [in squeak]

+1  A: 

The normal way a user does this is to modify the method source and 'accept it' then delete the old version. So it's not likely that basic Squeak includes a single method to do this, although I could be wrong.

However if you install, for example, OmniBrowser there is a method refactoring called 'rename' and you could inspect and find code to perform this refactoring. It is fairly complex, firstly because the refactorings are done using the command pattern which involves a little redirection to work out, but secondly because this is a fairly complex refactoring which includes modifying the call sites.

Ken Causey
+3  A: 

What you are suggesting puts HUGE red flags up for me. What is it you are trying to accomplish with this?

Do you mean you want to change the name of the method you are calling at runtime? If so, that's easy.

do something like:

|methodName|
methodName :=  self useMethod1 ifTrue: [#method1 ] ifFalse:[ #method2 ].
self perform: methodName.
Curtis
A: 

Avoid voodoo magic in real code when possible.

That being said you can do some very interesting things by manipulating methods dynamically.

For instance the code bricks in Etoys are translated into Smalltalk methods. Other DSL implementations can also benefit from similar metaprogramming tricks.

After experimenting a bit I came up with the following code for renaming unary methods:

renameMethod: oldMethod inClass: class to: newMethod
| oldSelector newSelector source parser |

oldSelector := oldMethod asSymbol.
newSelector := newMethod asSymbol.
oldSelector = newSelector ifTrue: [^self].

"Get method category"
category := (LocatedMethod location: class selector: oldSelector) category.

"Get method source code"
source := class sourceCodeAt: oldSelector.

"Replace selector in method source" 
(parser := class parserClass new) parseSelector: source.
source := (newSelector asString), (source allButFirst: parser endOfLastToken).

"Compile modified source"
class compile: source classified: category.

"Remove old selector"
class removeSelector: oldSelector

You could probably find an easier way to do this if you browse through the Squeak code a bit longer than I did.

Alexandre Jasmin
+1  A: 

You best use a refactoring

r := RenameMethodRefactoring 
 renameMethod: #foo:foo: 
 in: Foo
 to: #bar:bar:
 permutation: (1 to: #foo:foo: numArgs). 
r execute.
Adrian