-
-
Notifications
You must be signed in to change notification settings - Fork 356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ExtractTempDriver #17168
ExtractTempDriver #17168
Conversation
Thanks a lot! |
I will try to find some time to have a look. |
Okay, thank you @Ducasse, I appreciate it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Sandra, this looks good on quick skim. To make this complete you need to make extract temp command actually use this driver.
- Find the command class and do required changes to make it use driver instead of refactoring
- Migrate any UI from command to driver
- Create at least a happy path test for this driver, if already done, create a test with invalid selection or invalid variable name
… insted of the refactroing class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really nice work, left some minor comments, nothing too huge. Well done!
|
||
self setUpDriver: driver. | ||
|
||
self should: [ driver runRefactoring ] raise: Error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if we would expect as specific error as possible. I'm guessing this is RBRefactoringError
?
|
||
self setUpDriver: driver. | ||
|
||
self should: [ driver runRefactoring ] raise: Error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above
firstCondition check ifFalse: [ | ||
self setErrorTextFromCondition: firstCondition onPresenter: presenter ]. | ||
secondCondition check ifFalse: [ | ||
self setErrorTextFromCondition: secondCondition onPresenter: presenter ]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If they both fail, it will only show the error text from the second one, right?
{ #category : 'execution' } | ||
ReExtractToTemporaryDriver >> requestSelector [ | ||
|
||
^ self requestUserInput: 'Please provide a selector' | ||
label: 'The selector should be defined.' | ||
validate: [ :string :presenter | self validateSelector: string onPresenter: presenter ] | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two things here, both are non-blocking:
- since Driver should only be called through UI, chances that selector is invalid are close to 0, so this check is optional in the driver and will always pass
- correct way of asking user for selector would be to use selection presenter that you fill with available selectors from the class, but again this is not needed since this will be correctly set always
This check is important when we are invoking this refactoring programatically, and it should then raise an exception, and not ask for new selector.
My suggestion might be to remove this code from driver. Would like to hear you thoughts as well @Ducasse
ReExtractToTemporaryDriver >> validateName: aName onPresenter: presenter [ | ||
|
||
| firstCondition secondCondition result | | ||
firstCondition := ReIsValidInstanceVariableName new name: aName. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to ask refactoring for preconditions like: refactoring preconditionValidInstVarName
and refactoring preconditionCheckVariableName
that way we can reduce duplication and avoid potential misconfiguration.
SycExtractTempCommand >> asRefactorings [ | ||
|
||
^ {RBExtractToTemporaryRefactoring | ||
extract: sourceNode sourceInterval | ||
to: tempName | ||
from: method selector | ||
in: method origin} | ||
| driver | | ||
driver := ReExtractToTemporaryDriver new. | ||
driver | ||
extract: sourceNode sourceInterval | ||
to: tempName | ||
from: method selector | ||
in: method origin. | ||
|
||
^ driver runRefactoring. | ||
|
||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take a look at how were other drivers configured to run here. This does work, but there is a slightly better way:
- override
isComplexRefactoring
to return false - this method is unused then
- override
execute
with this code
Take a look atSycRemoveClassCommand
. I'm saying this sinceasRefactoring
andisComplexRefactoring
will be removed in the future and this will then not work.
…o provide better understand and woking tests. Removeing unsed or methods that are not needed.
I deleted the dialog related to the selector as you suggested @balsa-sarenac , before I didn't consider that there might not be a need for it, my mistake. If @Ducasse thinks otherwise, it's not a problem for me to add it again and change it so that it's an optional dialog. |
src/Refactoring-UI-Tests/ReExtractToTemporaryDriverTest.class.st
Outdated
Show resolved
Hide resolved
src/SystemCommands-SourceCodeCommands/SycExtractTempCommand.class.st
Outdated
Show resolved
Hide resolved
{ #category : 'execution' } | ||
ReExtractToTemporaryDriver >> requestVariableName [ | ||
|
||
newVariableName := self defaultRequestDialog |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that source of your errors are the mocks. They are very tricky. Basically here we use defaultRequestDialog
. We send it message title:
, label:
and validateAnswer:
. We need mock for it that will answer for example self
for first two, and on validateAnswer:
it will answer newVariableName
that we want.
] | ||
|
||
{ #category : 'accessing' } | ||
ReExtractToTemporaryDriver >> variableNameEditorPresenterClass [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this function's name should be defaultRequestDialog
? Can you check how rename method did this mocking, might be helpful. If needed we can pair on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used rename method as an example, it has methodNameEditorPresenterClass
method. Rename method uses a requestDialogWith:
and I just made a default one, I saw an example of it in the rename class refactoring. Now I see that my focus should be there, thank you @balsa-sarenac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought so, thats why I asked if you need both mocks. If you need help, reach out. Try to debug rename method to see exactly how was mock set up, and then with that knowledge create mock specific to this use-case.
dialog := MockObject new. | ||
|
||
dialog | ||
on: #variableName | ||
respond: (RBArgumentName name: 'tempVar'). | ||
|
||
dialog | ||
on: #variableName | ||
respond: (RBArgumentName name: #anotherVar). | ||
|
||
driver requestDialog: dialog. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We craft these mocks based on how they are used in the driver. I'm not sure they are configured correctly. Basically what we do is create mock object. Go in the class and see exactly which messages are sent to this object. Each of them define here in on:respond:
. Pay attention which message should return something meaningful, and which ones you don't care (if you don't care, return self
).
For example requestDialog:
receives name:
, label:
and validateAnswer:
, right?
Main disadvantage of mocks is that they are tightly coupled to implementation and I'm not a big fan of them, but this is only way we found to test drivers.
src/Refactoring-UI-Tests/ReExtractToTemporaryDriverTest.class.st
Outdated
Show resolved
Hide resolved
…ons. Removing a method that is not used anymore, fixing validation messages.
… Creating a new dialog
…ng needed changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/Refactoring-UI-Tests/ReExtractToTemporaryDriverTest.class.st
Outdated
Show resolved
Hide resolved
newVariableName := self requestVariableName. | ||
refactoring extract: sourceInterval to: newVariableName from: selector in: class. | ||
shouldEscape ifTrue: [ ^ self ]. | ||
refactoring preconditionValidInstVarName check ifFalse: [ ^ self ]. | ||
refactoring preconditionCheckVariableName check ifFalse: [ ^ self ]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you don't have while false here anymore, and you are still using shouldEscape
, is this on purpose? What happens when user types wrong name, do we offer it to give us new name with a helpful error message?
src/SystemCommands-SourceCodeCommands/SycExtractTempCommand.class.st
Outdated
Show resolved
Hide resolved
…ts on StVariableNameEditorPresenterClass. Updaing code
…iting presenter to work and look better. Editing method names and lebel texts
nearly there! |
testFailureInvalidVariableNameWhenVariableIsAlreadyTemporary is failing |
I could also integrate and skip that test. Let me know |
@Ducasse the dialog is not working very well, so my focus is on that now. I will let you know when I fix the dialog so you can integrate it then we will see what is wrong with the tests |
Super. Keep us up to date. |
Hello do you have some update? |
Hello @Ducasse, unfortunately I have been caught up with other commitments, which has slowed down my pace. Thankfully, these other obligations are getting resolved, and I hope that I will fix the dialog by Thursday. I apologize to keep you waiting. |
I am sorry @Ducasse , I still haven't been able to fix the problems. There are two problems :
It is possible that there are some other mistakes that I did not see. I don't do well with the presenter, not sure if the presenter is the problem or |
Ok no problem. |
Maybe it is possible, but I am not sure how big the problems are @Ducasse. When the refactoring is started, a dialog appears, which is created using the presenter class, if the precondition is not met, an error message should be displayed in the dialog, I set the error message to a label in the presenter but I am not sure how to print it. This is the first problem, the second problem is when the correct variable is entered and the refactoring should happen there are no changes, the variable should be created and have the value of the selected interval but that is not the case, I don't know why. |
Ok @balsa-sarenac do you have some cycles for this? |
@balsa-sarenac when I integrated this PR it broke the build Error: Package Refactoring-UI depends on the following classes: I will add RBInteractionDriver to be able to load it. |
Creating an interaction driver for RBExtractToTemporaryRefactoring