Reputation: 1365
Situation: I'm working on legacy code and trying to improve readability. The following example should visualize the intent:
private static final String CONSTANT_1 = "anyValue";
private static final String CONSTANT_2 = "anyValue";
private static final String CONSTANT_3 = "anyValue";
private static final String CONSTANT_4 = "anyValue";
private static final String CONSTANT_5 = "anyValue";
private final SomeType someField = new SomeType();
private void contentOfSomeMethods(){
someMethod(someField, CONSTANT_1, true);
someMethod(someField, CONSTANT_2, true);
someMethod(someField, CONSTANT_3, true);
someMethod(someField, CONSTANT_4, false);
someMethod(someField, CONSTANT_5, false);
}
private void someMethod(SomeType type, String value, boolean someFlag) { }
Imagine, there are about 50 calls of someMethod using about 50 constants. I want to do safe automatical refactorings on that code so that the contentOfSomeMethods
method changes to
private void contentOfSomeMethods(){
doItWith(CONSTANT_1);
doItWith(CONSTANT_2);
doItWith(CONSTANT_3);
doItNotWith(CONSTANT_4);
doItNotWith(CONSTANT_5);
}
and two additional methods are generated:
private void doItWith(String value) {
someMethod(someField, value, true);
}
private void doItNotWith(String value) {
someMethod(someField, value, false);
}
The naive way is to extract all constants in contentOfSomeMethods
inside local variables and use then the extract method refactoring to create the desired methods. And afterwards to inline back the local variables. But this solution doesn't scale up.
Another way is to use search and replace with regular expressions, but this is not a safe refactoring, so I could break the code without noticing it.
Do you have any better suggestions? Do you know some plugins for Eclipse that allow that?
Upvotes: 3
Views: 843
Reputation: 787
Alas I know nothing in Eclipse that allows to do this today. This is something I would like to achieve one day in AutoRefactor: https://github.com/JnRouvignac/AutoRefactor/issues/8
However the road to get there is quite long.
The only ways I know today are to extract local variables then extract method (as you suggested) or use regexes (as somebody else suggested).
Upvotes: 0
Reputation: 3200
Do it with a regular expression and verify it.
I'm assuming that each call to someMethod
spans only one line. If not this method is still useful but slower.
Copy the original file.
Use ctrl+alt+h to show the Callers of someMethod
and get a count of them.
Do regex search and replaces restricted to the proper area :
Find : someMethod(someField,([ ]*CONSTANT_[0-9]+)[ ]*,[ ]*true[ ]*)[ ]*;
Replace : doItWith("$1");
Find : someMethod(someField,([ ]*CONSTANT_[0-9]+)[ ]*,[ ]*false[ ]*)[ ]*;
Replace : doItNotWith("$1");
Make a diff of the original file and the new file showing only the lines of the original file which have changed.
diff --changed-group-format='%<' --unchanged-group-format='' original.java refactored.java | wc
You should get the same number of lines as you got in the callers of someMethod.
If the calls to someMethod are multiline, or if you want greater verification, just drop | wc
to see the lines which were modified in the original file to ensure that only the correct lines have been modified.
Upvotes: 0
Reputation: 137299
I don't know of any utility that would do this directly.
I think using a regular expression is the only to go. First, you will need to create the two target methods doItWith
and doItNotWith
. Then, you can highlight the contents of the method contentOfSomeMethods
, hit Ctrl+F, and use the following regular expressions:
Find:
someMethod\(someField, (\w*), true\);
Replace with:doItWith(\1);
and then
Find:
someMethod\(someField, (\w*), false\);
Replace with:doItNotWith(\1);
Be sure to check "Regular Expressions" and "Selected lines". Here's a picture of it:
The regular expressions match the constant that is used inside the function call with (\w*)
and then it is used during the replacement with \1
. Using this regular expression only on the selected lines minimizes the chance of breaking unrelated code.
Upvotes: 1