(Move categories to tip template) |
(Remove html character entities) |
||
Line 110: | Line 110: | ||
This has the advantage that our new function is also available for other similar purposes. |
This has the advantage that our new function is also available for other similar purposes. |
||
− | I will create the new class also with the help of Vim, the actual extracting of the method into the new class is just a matter of copy & |
+ | I will create the new class also with the help of Vim, the actual extracting of the method into the new class is just a matter of copy & paste. |
Here is the Vim code: |
Here is the Vim code: |
||
<pre> |
<pre> |
||
− | vmap \em :call ExtractMethod() |
+ | vmap \em :call ExtractMethod()<CR> |
function! ExtractMethod() range |
function! ExtractMethod() range |
||
let name = inputdialog("Name of new method:") |
let name = inputdialog("Name of new method:") |
||
− | ' |
+ | '< |
− | exe "normal! O\ |
+ | exe "normal! O\<BS>private " . name ."()\<CR>{\<Esc>" |
− | ' |
+ | '> |
− | exe "normal! oreturn ;\ |
+ | exe "normal! oreturn ;\<CR>}\<Esc>k" |
s/return/\/\/ return/ge |
s/return/\/\/ return/ge |
||
normal! j% |
normal! j% |
||
normal! kf( |
normal! kf( |
||
− | exe "normal! yyPi// = \ |
+ | exe "normal! yyPi// = \<Esc>wdwA;\<Esc>" |
normal! == |
normal! == |
||
normal! j0w |
normal! j0w |
||
Line 157: | Line 157: | ||
<pre> |
<pre> |
||
"Create property |
"Create property |
||
− | imap |
+ | imap <C-c><C-p><C-s> <Esc>:call CreateProperty("string")<CR>a |
− | imap |
+ | imap <C-c><C-p><C-i> <Esc>:call CreateProperty("int")<CR>a |
function! CreateProperty(type) |
function! CreateProperty(type) |
||
− | exe "normal bim_\ |
+ | exe "normal bim_\<Esc>b\"yywiprivate ".a:type." \<Esc>A;\<CR>public ".a:type. |
− | \ " \ |
+ | \ " \<Esc>\"ypb2xea\<CR>{\<Esc>oget\<CR>{\<CR>return " . |
− | \ "\ |
+ | \ "\<Esc>\"ypa;\<CR>}\<CR>set\<CR>{\<CR>\<Tab>\<Esc>\"yPa = value;\<CR>}\<CR>}\<CR>\<Esc>" |
normal! 12k2wi |
normal! 12k2wi |
||
endfunction |
endfunction |
||
Line 226: | Line 226: | ||
<pre> |
<pre> |
||
"Create abstract class |
"Create abstract class |
||
− | imap |
+ | imap <C-c><C-a><C-c> <Esc>bipublic abstract class <Esc>A<CR>{<CR>public abstract void X();<CR>}<Esc>:?X<CR>0fXs |
"Create concrete class |
"Create concrete class |
||
− | map |
+ | map <C-c><C-c><C-c> :silent! call ImplementAbstractClass()<CR> |
function! ImplementAbstractClass() range |
function! ImplementAbstractClass() range |
||
− | exe "normal \ |
+ | exe "normal \<Esc>\"yyw" |
/{ |
/{ |
||
normal "xy% |
normal "xy% |
||
normal %o |
normal %o |
||
− | exe "normal! \ |
+ | exe "normal! \<Esc>o" |
let name = inputdialog("Name of new method:") |
let name = inputdialog("Name of new method:") |
||
− | exe "normal! ipublic class " .name." : \ |
+ | exe "normal! ipublic class " .name." : \<Esc>\"yp\"xp" |
− | exe "normal! }O}\ |
+ | exe "normal! }O}\<Esc>==" |
normal %v% |
normal %v% |
||
normal! gv |
normal! gv |
||
− | ' |
+ | '<,'>s/abstract/override/g |
normal! gv |
normal! gv |
||
− | ' |
+ | '<,'>s/;/\r{\r}\r/g |
normal! == |
normal! == |
||
normal %kdd%k |
normal %kdd%k |
||
Line 255: | Line 255: | ||
<pre> |
<pre> |
||
− | imap |
+ | imap <C-c><C-p> <Esc>:call CreateProperty()<CR>a |
function! CreateProperty() |
function! CreateProperty() |
||
− | exe "normal bim_\ |
+ | exe "normal bim_\<Esc>b\"yyybiprivate \<Esc>A;\<CR>\<Esc>\"ypw\"xyw\<Esc>2xbipublic \<Esc>$a\<CR>{\<Esc>oget\<CR>{\<CR>return \<Esc>\"xpa;\<CR>}\<CR>set\<CR>{\<CR>\<Tab>\<Esc>\"xPa = value;\<CR>}\<CR>}\<CR>\<Esc>" |
normal 12k2wi |
normal 12k2wi |
||
endfunction |
endfunction |
||
</pre> |
</pre> |
||
− | This will create a property from a '' |
+ | This will create a property from a ''<type> <Field Name>''. This alleviates the need for multiple mappings for each data type in the vimrc file |
− | So if you want to create a property from <tt>Rectangle Box</tt> just press <tt> |
+ | So if you want to create a property from <tt>Rectangle Box</tt> just press <tt><C-c><C-p></tt> and you get |
<pre> |
<pre> |
Revision as of 09:00, 29 September 2008
created October 16, 2003 · complexity intermediate · author Klaus Horsten · version 6.0
You can use Vim as a refactoring tool. The advantages are:
- You automate repetitive writing tasks.
- You learn refactoring.
You can expect much from a refactoring tool but if you have a look at the commercial refactoring tools there is much (not all!) Vim can do too.
I give you three examples, all in C#.
Example 1: The Extract Method refactoring
Sphagetti code example:
public string CreateMenu(string startMenu,string file) { string strOutput = ""; int i = 0; ArrayList startArray = new ArrayList(); string strVariable = ""; string strTemp = ""; XmlDocument XMLDoc = new XmlDocument(); try { XMLDoc.Load(file); } catch (Exception e) { strOutput = e.GetBaseException().ToString(); return strOutput; } XmlNodeList nodeList = XMLDoc.DocumentElement.ChildNodes; ...
Imagine 50 lines of code here.
Use the extract method refactoring to make a composed method.
I use a Vim function (see below) to build the exracted method.
I highlight the code part I want to extract and press \em (for extract method).
A dialog appears and asks me how to name the new method.
I type in "GetXmlDocumentFrom" and do get this:
// = GetXmlDocumentFrom(); private GetXmlDocumentFrom() { XmlDocument XMLDoc = new XmlDocument(); try { XMLDoc.Load(file); } catch (Exception e) { strOutput = e.GetBaseException().ToString(); return strOutput; } // return ; }
Now I have time to think what parameters the method needs and what to return.
I end up with the following function and remove it from the original function:
private XmlDocument GetXmlDocumentFrom(string XmlFile) { XmlDocument XMLDoc = new XmlDocument(); string strOutput = ""; try { XMLDoc.Load(XmlFile); } catch (Exception e) { strOutput = e.GetBaseException().ToString(); ErrorMessage(strOutput); } return XMLDoc; }
In the original code I put two lines.
XmlDocument XMLDoc = new XmlDocument(); XMLDoc = GetXmlDocumentFrom(XmlFile);
So I reduced the original code for 8 lines and made it clearer what the code does.
I do this with the rest of the code again and again.
Since the class gets bloated because of the many new methods I later will use the Extract Class refactoring to put this method in an own XmlDocument-class.
This has the advantage that our new function is also available for other similar purposes.
I will create the new class also with the help of Vim, the actual extracting of the method into the new class is just a matter of copy & paste.
Here is the Vim code:
vmap \em :call ExtractMethod()<CR> function! ExtractMethod() range let name = inputdialog("Name of new method:") '< exe "normal! O\<BS>private " . name ."()\<CR>{\<Esc>" '> exe "normal! oreturn ;\<CR>}\<Esc>k" s/return/\/\/ return/ge normal! j% normal! kf( exe "normal! yyPi// = \<Esc>wdwA;\<Esc>" normal! == normal! j0w endfunction
Example 2: The Self Encapsulate Field refactoring
I have heard a programmer who just uses Visual Studio (nothing against Visual Studio, it's a great tool!) say: "I do not use properties. It's too much work." He just uses fields instead.
With Vim it is no problem to write a property, that is, to use the Self Encapsulate Field refactoring.
I write a name e.g. Name press CTRL-C CTRL-P CTRL-S (create property with string). Voila, the new property appears in just a second:
private string m_Name; public string Name { get { return m_Name; } set { m_Name = value; } }
Here are the Vim mappings and the underlying function:
"Create property imap <C-c><C-p><C-s> <Esc>:call CreateProperty("string")<CR>a imap <C-c><C-p><C-i> <Esc>:call CreateProperty("int")<CR>a function! CreateProperty(type) exe "normal bim_\<Esc>b\"yywiprivate ".a:type." \<Esc>A;\<CR>public ".a:type. \ " \<Esc>\"ypb2xea\<CR>{\<Esc>oget\<CR>{\<CR>return " . \ "\<Esc>\"ypa;\<CR>}\<CR>set\<CR>{\<CR>\<Tab>\<Esc>\"yPa = value;\<CR>}\<CR>}\<CR>\<Esc>" normal! 12k2wi endfunction
You can combine Visual Studio and Vim. You can work in Visual Studio and load the file in Vim for refactoring. I have made a menu entry in Visual Studio that loads the actual file I am writing in Vim (cf. VimTip580).
Example 3: The Replace Conditional with Polymorphism refactoring
Imagine a switch and you want to replace it with an abstract class and some concrete classes which inherit from this parent class.
You may think "Why should I replace this switch? It's too much work. Writing all these classes ..."
With Vim it's just a question of a few seconds.
To build the abstract class I type, say Fruit.
Then I press CTRL-C CTRL-A CTRL-C (create abstract class) and get
public abstract class Fruit { public abstract void |(); } | is the cursor position
Now I fill in the methods.
public abstract class Fruit { public abstract void Taste(); public abstract void Color(); public abstract string GetSize(); }
Now I go on the first letter of Fruit and type CTRL-C CTRL-C CTRL-C (create concrete class).
A dialog appears and asks me for the new name of the concrete class. I type in Apple and get
public class Apple : Fruit { public override void Taste() { } public override void Color() { } public override string GetSize() { } }
I continue doing so with all the child classes of the abstract class.
In this way I get code templates that I can implement now.
Here are my mappings and the underlying funtion.
"Create abstract class imap <C-c><C-a><C-c> <Esc>bipublic abstract class <Esc>A<CR>{<CR>public abstract void X();<CR>}<Esc>:?X<CR>0fXs "Create concrete class map <C-c><C-c><C-c> :silent! call ImplementAbstractClass()<CR> function! ImplementAbstractClass() range exe "normal \<Esc>\"yyw" /{ normal "xy% normal %o exe "normal! \<Esc>o" let name = inputdialog("Name of new method:") exe "normal! ipublic class " .name." : \<Esc>\"yp\"xp" exe "normal! }O}\<Esc>==" normal %v% normal! gv '<,'>s/abstract/override/g normal! gv '<,'>s/;/\r{\r}\r/g normal! == normal %kdd%k endfunction
Comments
These are amazing! I never thought of doing this, but I have to say your tips are quite amazing! I have not begun to use hints 1 and 2 religiously, especially when I have to dig around through code that others have written! Thank you!!
Here is a variation
imap <C-c><C-p> <Esc>:call CreateProperty()<CR>a function! CreateProperty() exe "normal bim_\<Esc>b\"yyybiprivate \<Esc>A;\<CR>\<Esc>\"ypw\"xyw\<Esc>2xbipublic \<Esc>$a\<CR>{\<Esc>oget\<CR>{\<CR>return \<Esc>\"xpa;\<CR>}\<CR>set\<CR>{\<CR>\<Tab>\<Esc>\"xPa = value;\<CR>}\<CR>}\<CR>\<Esc>" normal 12k2wi endfunction
This will create a property from a <type> <Field Name>. This alleviates the need for multiple mappings for each data type in the vimrc file
So if you want to create a property from Rectangle Box just press <C-c><C-p> and you get
private Rectangle m_Box; public Rectangle Box { get { return m_Box; } set { m_Box = value; } }
I am still trying to get rid of some extra spaces in property name but I hope this helps