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
Refactorings in Pharo work on their own code meta-model.
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.
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.
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 ].
we can get this:
RBReadBeforeWrittenTester >>> copyDictionary: aDictionary
^aDictionary copyWithAssociationsDictionary >>> 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 receiver |
receiver := Object new.
a := receiver asString.
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 ...
Then according to the suggestion of my mentors, review Spec2 and Commander2 this because Pharo 8 is in the process of migrating from Spec (is a framework in Pharo for describing user interfaces) to Spec2 all the views and from Commander (it is a tool that serves to menu management) to Commander2.
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:
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.
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
Before I started describing what I did, I must explain to them why this happened, in my initial proposal I had to implement the inline methods the first month, however these were already implemented, so I decided to advance tasks that I had in my timeline, so I decided perform the renaming of parameters when extracting a method, and at the suggestion of my mentors I made a prototype of the creation of an interactive layer.
- 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.
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