New refactorings for Pharo 9

EVELYN CUSI LOPEZ
4 min readMay 3, 2021

These months I was working fixing and introducing new refactorings.

Below is a list of the new refactorings introduced:

1. Extract setUp method

I’m a refactoring for creating a setUp method from a code fragment.

You can select an interval of some code in a test method and call this refactoring to create a setUp method implementing that code and replace the code with nothing.

The selected class needs to be a subclass of TestCase.

The preconditions are quite complex.

- The code needs to be parseable valid code.

- The class must not implement the setUp method.

- Class must inherit from TestCase class

Example

Before refactoring:

TestCase subclass: #RBDataTestinstanceVariableNames: ‘’classVariableNames: ‘’package: ‘Example’.RBDataTest >> someMethod#someMethod.RBDataTest >> testExampleself someMethod.self assert: true.

After refactoring:

RBDataTest >> setUpsuper setUp.self someMethod.RBDataTest >> testExampleself assert: true.

Video: https://youtu.be/feKsdci0dL4

2. Remove senders of method refactoring

I am a refactoring to remove all possible senders from a method (you cannot remove those calls where the result of the method call is used or when the method name symbol is referenced).

Example

Remove all senders of printString

Before refactoring:

RBRefactoryTestDataApp >> caller1| anObject |anObject := 5.self called: anObject + 1on1:[:each |each printString.^anObject]

After refactoring (notice that the call to printstring was removed):

RBRefactoryTestDataApp >> caller1 | anObject |anObject := 5.self called: anObject + 1 on1: [:each |^anObject]

Video: https://youtu.be/nMJiyy8US8U

3. Copy package as refactoring

I am a refactoring to copy a package.

My preconditions verify, that the copied package exists (in the current environment) and that the new copy package name is valid and not yet used as a global variable name

The refactoring transformation create a new package and copy defined classes of origin package (exclude all class’ extensions)

Example

The following package has these classes,

Image: Package content

and these classes has these references between them:

MyClassA >> foo^ MyClassBMyClassB >> example4#MyClassA1

After copy #Example package we obtain this result:

Image: Contents copied package

and references were updated

MyClassACopy >> foo^ MyClassBCopyMyClassBCopy >> example4#MyClassA1Copy

It can also be noted that the hierarchy was correctly updated with the copied classes.

4. Rename package (rename manifest)

I’m a refactoring to rename a package.

My preconditions verify that the new name is different from the current package name and is a valid name.

I change all the references of the classes that are defined within the package, and if there is a manifest, it is updated with the new name of the package.

Video: https://youtu.be/94qlZmmIMwY

5. Merge instance var into another

I am a refactoring for merge an instance variable into another.

I replace an instance variable by another, in all methods referring to this variable and rename the old accessors, then if the instance variable renamed is directly defined in class it is removed.

My precondition verifies that the new variable is a defined instance variable in class.

Example

Before refactoring:

Class Foo -> inst vars: x, yFoo >> foobar^ xFoo >> foo^ x + y

After refactoring merging X into Y

Class Foo -> inst vars: yFoo >> foobar^ yFoo >> foo^ y + y

Video: https://youtu.be/sntrzsHCW9A

6. Move to class side method

I’m a refactoring to move a method to the class side.

My preconditions verify that the method exists and belongs to instance side.

I catch broken references (method senders and direct access to instVar) and fix them.

Example

Before refactoring (move #rewriteUsing: to class side):

RBTransformationRuleTestData >> rewriteUsing: searchReplacerrewriteRule := searchReplacer.self resetResult.

After refactoring:

RBTransformationRuleTestData >> rewriteUsing: searchReplacer^ self class rewriteUsing: searchReplace.RBTransformationRuleTestData class >> rewriteUsing: searchReplacer| aRBTransformationRuleTestData |aRBTransformationRuleTestData := self new.aRBTransformationRuleTestData rewriteRule: searchReplacer.aRBTransformationRuleTestData resetResult.

7. Create accessors with lazy initialization

I’m a refactoring for creating accessors with lazy initialization for variables.

I am used by a couple of other refactorings creating new variables and accessors.

My precondition is that the variable name is defined for this class.

Example

Before refactoring:

Object subclass: #RBLintRuleTestDatainstanceVariableNames: ‘name foo1’classVariableNames: ‘Foo1 Name1’poolDictionaries: ‘TextConstants’package: ‘Refactoring-Tests-Core-Data’

After refactoring we get:

RBLintRuleTestData >> foo1^ foo1 ifNil: [foo1 := 123]RBLintRuleTestData >> foo1: anObjectfoo1 := anObject

Video Example: https://youtu.be/SO0G6f1Y0fk

That’s all for this post, goodbye and happy coding :)

--

--