Skip to content

Improve UI for class rename refactoring and add tests - #19941

Open
Biljcica wants to merge 15 commits into
pharo-project:Pharo15from
Biljcica:renameClassRefactoring2
Open

Biljcica wants to merge 15 commits into
pharo-project:Pharo15from
Biljcica:renameClassRefactoring2

Conversation

@Biljcica

Copy link
Copy Markdown

Improved the class rename refactoring UI with live validation and preview. The new name is validated as the user types, behavior-preserving preconditions are displayed when applicable, and the preview is updated with the current changes. Added tests for the new behavior.

@Ducasse

Ducasse commented Aug 31, 2026

Copy link
Copy Markdown
Member

Let us know when this is ready for integration

@Biljcica
Biljcica marked this pull request as ready for review September 10, 2026 11:04

@balsa-sarenac balsa-sarenac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome, very close to merge, all comments are minor. Good job!

Comment on lines +45 to +48
self
should: [ refactoring checkApplicabilityPreconditions ]
raise: Error
]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to be explicit here:

Suggested change
self
should: [ refactoring checkApplicabilityPreconditions ]
raise: Error
]
self
should: [ refactoring checkApplicabilityPreconditions ]
raise: RefactoringError
]

refactoring := driver instantiateRefactoring.
refactoring newName: driver newName .

self assert: driver checkApplicabilityPreconditions isNil

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have a better check for this? I'm not even sure isNil is fully correct here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the isNil check with applicabilityPreconditionsAreSatisfied to make the intention of the test clearer.

Comment on lines +37 to +41
driver newName: #NewClassName.
driver createAndSetNewRefactoring.

presenter updateBehaviorPanelVisibility: 'NewClassName'.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to send the new name both to the driver and to the presenter?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new name is now handled directly by the presenter, avoiding the need to set it on the driver as well.

Comment on lines +49 to +51
failedCondition := refactoring applicabilityPreconditions
detect: [ :condition | condition check not ]
ifNone: [ nil ].

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have this implemented:

Suggested change
failedCondition := refactoring applicabilityPreconditions
detect: [ :condition | condition check not ]
ifNone: [ nil ].
failedCondition := refactoring failedApplicabilityPreconditions.

detect: [ :condition | condition check not ]
ifNone: [ nil ].

^ failedCondition ifNotNil: [ :condition | condition errorString ]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly this as well with applicabilityViolationMessage? If not, we should think of introducing one.

Comment on lines +80 to +81
^ self refactoring breakingChangePreconditions
anySatisfy: [ :each | each check not ]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
^ self refactoring breakingChangePreconditions
anySatisfy: [ :each | each check not ]
^ self refactoring failedBreakingChangePreconditions isEmpty

Comment on lines +332 to +341
StRenameClassPreviewPresenter >> performChanges [
"the following behavior should not be kept in the UI.
It should be moved to the driver or the refactoring itself because the driver is a model of interaction.
May be this should be in the refactoring."

[ ReChangeManager instance
performChanges: selectedChanges ]
asJob
title: 'Refactoring';
run

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. It should be something like this:

Suggested change
StRenameClassPreviewPresenter >> performChanges [
"the following behavior should not be kept in the UI.
It should be moved to the driver or the refactoring itself because the driver is a model of interaction.
May be this should be in the refactoring."
[ ReChangeManager instance
performChanges: selectedChanges ]
asJob
title: 'Refactoring';
run
StRenameClassPreviewPresenter >> performChanges [
driver performChanges: selectedChanges.

Then Driver should have something like:

ReRenameClassDriver2 >> performChanges: selectedChanges

	[ ReChangeManager instance
			performChanges: selectedChanges ]
		asJob
		title: 'Refactoring';
		run

BUT, this can be also delegated to refactoring, if we want the driver to be the sole controller:

ReRenameClassDriver2 >> performChanges: selectedChanges
	refactoring performChanges: selectedChanges

The refactoring already has performChagnes that does exactly what UI was duplicating. So it makes sense to have performChagnes: as well.
This can be done in future PR, let's keep this one Rename Class focued.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, noted!


self closeWindow ].
self performChanges.
self updateGlobalActiveScope.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why we need this after performing changes? This might be bug in the old system as well. We should check if it works without this and what's the bug if it doesn't work. Also, a separate PR not to be done here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested without this, and the changes are not performed. After clicking Apply, the name remains unchanged.

applyButton := aDialogWindowPresenter addDefaultButton: 'Apply' do: [ :presenter |
self terminateUpdateProcess.
self accept.
presenter close ].

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here we do presenter close but we also defined closeWindow so it's a bit confusing, but ok, we can clean later

Comment on lines +345 to +346
StRenameClassPreviewPresenter >> refactoring: aRBRemoveMethodDriver [
refactoring := aRBRemoveMethodDriver

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either change this to driver: or rename argument to aRenameClassRefactoring (i think the first one?)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the argument to aRenameClassRefactoring, since a driver: method already exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants