Better and more refactorings for Pharo — Part 3

This is a post summary of my first month in the GSoC program. Then let’s get started…

In the first stage, I mainly did 3 things: understand how Pharo’s refactorings work internally, learn tools and finally make the first advances of my proposal. Below I will detail each of these.

Understanding how refactorings work

To execute a refactoring there are two ways: primitiveExecute and execute.

  • PrimitiveExecute: It consists of validating the preconditions of the refactoring (it should be noted that each refactoring has its own preconditions and these are generally defined by the RBCondition class) and then perform the necessary code transformation, however the changes made by the transformation are not yet implemented in the image of Pharo, that is, your image continues as it was before executing this method, below the primitiveExecute method is shown.
self checkPreconditions.
self transform

You can access the changes of the refactoring using the changes method. Generally this method is used in the execution of tests and in suggestions of the menu, since the latter shows you a preview of the changes in the refactoring, in which you can decide which ones to accept and which ones do not..

  • Execute: In the following fragment of code you can see the execute method, which is practically the execution of primitiveExecute with the difference that directly implements the changes, that is, it does not give you a preview of the changes and they are applied atomically.
self primitiveExecute.
RBRefactoryChangeManager instance performChange: self changes.

This method is used in the source code of the menu, with some exceptions.

Personally, it was difficult for me to understand it and it was in the part that cost me the most, but after reviewing the whole code I was amazed, because there are a lot of refactorings that I did not know existed, since they go beyond of the refactorings to which can be accessed through the commands (menus, shortcuts).

For example, the RBExtractMethodToComponentRefactoring class can extract methods even over other classes, for example:

Having this code fragment:

RBReadBeforeWrittenTester >>> copyDictionary: aDictionary 
“We could send aDictionary the copy message, but that doesn’t copy the associations.”
| newDictionary |
newDictionary := Dictionary new: aDictionary size.
aDictionary keysAndValuesDo: [ :key :value | newDictionary at: key put: value ].
^ newDictionary

we can get this:

RBReadBeforeWrittenTester >>> copyDictionary: aDictionary 
^aDictionary copyWithAssociations
Dictionary >>> copyWithAssociations
| newDictionary |
newDictionary := Dictionary new: self size.
keysAndValuesDo: [:key :value | newDictionary at: key put: value].

In the same way there is a refactoring (RBSplitCascadeRefactoring) that divides a message in cascade into several messages, for example given the following code fragment:

| a |
a := Object new initialize; asString.
^ a

we get:

| a receiver |
receiver := Object new.
receiver initialize.
a := receiver asString.
^ a

These are just a small fragment of everything that Pharo has, if you really like this topic I recommend you review it and I assure you that just like me, you will be fascinated.

Learn, learn and learn ...

Refactoring has few views, and I focused on collaborating by giving ideas with the Stage project (in which Pharo’s views from Spec to Spec2 were migrating) specifically in the refactoring views, resulting in:

Figure 1: Update of previews

However, these views are not yet integrated to Pharo, but soon they will be :D.

When I checked Commander2 I had the inconvenience that it does not have an adapter for Morphic yet, so I could not migrate the refactoring commands to Commander2.

Additionally my mentors suggested me to review MatchTool, which is a tool that allows you to test and explore RB matching expressions, it’s really interesting, do not even check it thoroughly but if you’re interested you can review it.

Figure 2: Preview MatchTool

I really did not know that I would review so many new tools in the realization of this project, sometimes you find things difficult to grasp the first, however you have to lose the fear of asking, so you can move faster and really the Pharo community is very helpful and I assure you that there will always be someone who is willing to help you in any doubt ;)

First advances of my proposal

  • Rename parameters: The first thing I did was modify the preview (SycMethodNameEditor2 of the Stage project) where the new name of the extracted method is defined, adding an editable text field when selecting a parameter.
Figure 3: Preview of extract method with option to rename parameters

Then add validators to accept the new name of the parameter, and finally add a method for the renaming of parameters in the transform method of RBExtractMethodRefactoring, so that it is already possible to rename the parameters when extracting a method. This change is not yet available in Pharo but you can see the changes made here .

  • Add interactive layer: This consists mainly of separating the logic from the refactoring of the views, for example, system commands is the one that handles the logic of which views to use to send the necessary parameters of the refactoring, which should not be the case. Which is why I’m working on it. These changes have not yet been approved, however if you want to give them a view you can do it from here and the modification of system commands if it is accept this would become as shown here.

I hope that my experience will help you to plan your tasks well and not be in the situation that I was due to the bad planning that I had for my first month, and above all I hope you liked this post.

That’s all for today’s publication, goodbye and happy coding :D



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store