Ruby Screenshot of the Week #23: Extract Method and More Refactorings!


Last week I promised to catch up on my e-mail, but I had been missing feature work too much during the bug phase so I put it off for a week... to implement some more quickfix refactorings:


  • Extract Method

  • Introduce Variable

  • Introduce Constant




Here's how it works. Let's start with "Extract Method". You're looking at some code like this:






You decide there's too much going on in this method, and you want to pull the middle section into
its own method. Select it, and notice the lightbulb which shows up on the left:






Press Alt-Enter to show the quick fix alternatives:






Select Extract Method, and the IDE will pop up a dialog asking you for the name of the new method you want to extract from the selected code fragment:






Press OK (or just hit Enter), and the code will mutate into the following:






There's a lot to notice here. First, there's a new method, and the active selection and caret is on a comment for that method (so you can just type to replace it). The new method is added below the one you extracted code from. And the most important part about this refactoring is that the IDE figures out which variables to pass in to the method, and which variables to pass back out:


  • a, b and d are accessed from within the fragment, so they are passed in.
  • c is reassigned in the fragment without reading the previous value, so
    doesn't need to be passed in.
  • f and h are assigned locally inside the extracted fragment, but are not read
    outside of it, so do not need to be passed back out
  • g is assigned inside the fragment, and read later outside, so it is returned
    from the new method but not passed in
  • h is assigned inside the fragment, and is read later, but it is assigned
    before this read access so the value doesn't need to be passed back
  • i is also assigned inside the fragment, and -may- be read after the fragment,
    so it too is passed back out



Ruby's multiple return values makes this refactoring much cleaner than in Java where you have
to jump through some hoops to extract code fragments that modify multiple local variables...



Now let's take a look at Introduce Constant. Let's say you're looking at code like this (unlike the above contrived example from one of my unit tests for Extract Method, the following is from
the standard Ruby Library's Date class):






There are a lot of "magic" numbers here. I honestly don't know what some of them are - but I recognize 365.25 as the number of days per year. Let's make that clearer - select that constant. (Tip - just move the caret to it and press Ctrl-Shift-Dot, which selects progressively larger logical elements around the caret). This produces the above lightbulb, so let's press Alt Enter again:






I can now choose to either introduce a field, or a variable, or a constant. A constant is most natural here. (You won't be offered constant if the selected code fragment is not a constant expression.) So choose Introduce Constant:






In the dialog asking for the name of the new constant, notice that it also detected some duplicates of this constant in the same class (3 of them to be exact), and asks if you want to replace all of them. I do - so I select the checkbox and press Ok:






The IDE has inserted a new constant at the top of the class, and has warped to it to let me edit a comment for the constant. I can also scroll down and see that the constants below were updated:






The search for duplicates only looks for single constants at the moment, not more complicated expressions - it will do that soon. As always, please report any bugs you encounter. This is in the daily 6.1 trunk builds, although I've deliberately kept the code 6.0 compatible such that I can put this out on the update center for 6.0 as well.

Comments:

This features looks great! I noticed on the ruby wiki that you will work more with code compleition, when is this planned? As a Delphi developer it's hard do manage without good code compleitition ;)

Posted by Jon Stenqvist on November 12, 2007 at 05:09 AM PST #

Brilliant work -- these are \*the\* killer refactorings, I am looking forward to Netbeans 6 final when I can finally ditch gvim for a real IDE! (With the vi plugin, of course :))

Posted by Greg on November 12, 2007 at 05:37 AM PST #

hi Tor! Excellent!! I have some question from another side - is there a way to increase the size of font in main menu of NetBeans, and also in the names of opened files, content of the project in the right panel? They look too small - really hardly to see on them. Thanks a lot!!

Posted by ruby.freeman on November 12, 2007 at 08:05 AM PST #

Jon, do you have any specific issues you'd like to see addressed first? Just smarter type inference in general? Or tracking of block variables, or ability for it to show operators when invoking completion between identifiers, etc?
<p>
Greg, thanks and let me know how the migration for gvim works out!
<p>
Freeman, try running NetBeans with the --fontsize argument, e.g. netbeans --fontsize 16 (you can specify the startup flag persistently by editing the etc/netbeans.conf file (or etc/nbrubyide.conf if you're running the distro from deadlock.netbeans.org).

Posted by Tor Norbye on November 12, 2007 at 08:47 AM PST #

Tor, thanks a lot for a quick respond! It works, many thanks, much better. Is there a way to force an antialiasing for NetBeans system fonts as it works for text-editor fonts?

Posted by ruby.freeman on November 12, 2007 at 09:05 AM PST #

I'm running it with -J-Dswing.aatext=true but fonts from menu are still non-aliased (but it's not so important of course), thanks for your work!!

Posted by ruby.freeman on November 12, 2007 at 09:32 AM PST #

There are small bugs in HAML module - I cannot set custom colors and fonts - when I set them, NetBeans opens file correctly, but after a second it loads default colors (bold instead of plain, etc.)

Posted by ruby.freeman on November 12, 2007 at 12:36 PM PST #

"...much cleaner than in Java where you have to jump through some hoops to extract code fragments..."

Which hoops would that be, wrap in Object[] or so? I've never really found a satisfying pattern for this, and going bean based is just class pollution.

Posted by Casper on November 13, 2007 at 12:05 AM PST #

Freeman, anti aliasing is supposed to be used automatically, as long as (1) you're using a recent Java 6 version, and (2) you've enabled it on the rest of your desktop. I forwarded your HAML comment to the HAML module developer, Dylan Bruzenak.

Casper, yes, precisely - there are several variations; one is to return in Object[] (which I don't like because of the lack of type safety), another is to have multiple "out" parameters; if I want to pass back an int and a boolean for example, I pass in a int[] and a boolean[] and I return the results in [0] of each array. (And I never do this in API code; in that case, there's a result object class.)

Posted by Tor Norbye on November 13, 2007 at 12:24 AM PST #

is 6.1 the nightly builds at http://deadlock.netbeans.org/hudson/job/ruby/ ? if not, where is it? :)

Posted by jer on November 13, 2007 at 03:57 AM PST #

Yes, the build on deadlock is 6.1, as is the official release engineering nightly builds here:

http://bits.netbeans.org/download/trunk/nightly/latest/

Posted by Tor Norbye on November 13, 2007 at 04:25 AM PST #

[Trackback] If you haven't tried calling Java classes from a JRuby application yet, here is a simple code snippet to get you started. Paste the following code into the Ruby shell (JRuby IRB), press Enter, and a small desktop app opens (To open the Ruby shell in th...

Posted by Insider Scoop From the Tutorial Divas on November 13, 2007 at 07:36 AM PST #

Once again thanks for all the great improvements! This product is very exciting and I absolutely love it. I've been using beta 1 but decided to switch to the nightly builds. Can I safely run the exe for the nightly builds and have to do any reconfiguring of svn or projects? Wasn't sure if it was safe to do this from beta 1? Thanks again Tor, great job.

Posted by paul on November 13, 2007 at 10:12 PM PST #

Hi Paul,
If you want to stay on stable bits, you can use Release Candidate 1 which was just released:
http://www.netbeans.org/community/releases/60/index.html

That won't include the extra hints but they should appear on the update center pretty soon.

Your userdir (where persistent settings for things like SVN are stored) is typically -not- migrated from milestone build to milestone build since some things change incompatibly during development; it's major version to major version compatibility that is a priority. So, you -may- have to do that setup over again. But as a simple fix you can try copying your userdir to a new location and invoking netbeans with --userdir /your/new/location and it will probably work.

Posted by Tor Norbye on November 13, 2007 at 11:27 PM PST #

Just updated again this morning, i still dont see the new refactoring stuff - i cleared out my userdir too... any idea why it's not showing up? :)

Posted by Jerrett on November 14, 2007 at 02:18 AM PST #

There are some possibilities - either you've found a bug such that the code you're selecting isn't properly recognized as a refactorable code fragment, or perhaps the module isn't installed at all. First, go to the Options dialog, the Ruby category, the "Hints" panel - and see if you get a lot of extra hints. (Selection-based hints like Extract Method won't be listed there, but you should see at least a dozen hints if you have the extras properly installed). If so, check whether the following code fragment generates a warning

x = 1
y = 2
if (x = y)
puts "Hello"
end

That should generate a warning if you have the latest build. If you do, then please mail me the exact code fragment you're selecting so I can see why the code finds a problem with it. (I examine code fragments and disable refactoring if you've selected something "unbalanced", or something containing code not eligible for extract method, such as code containing new method definitions etc.)

Posted by Tor Norbye on November 14, 2007 at 02:32 AM PST #

Is there a way to change the font type/size on the output and console windows? It's kind of hard for me to read the mongrel output, thanks.

Posted by paul on November 15, 2007 at 04:44 AM PST #

Hi paul!
Run NebBeans with these keys: "-J-Dswing.aatext=true --fontsize 18" - this will increase all the fonts in NetBeans, including the console, as well as turn on an antialiasing for them

Posted by ruby.freeman on November 15, 2007 at 08:41 AM PST #

I restarted my mac because of the system update, and now the refactoring stuff works.. very odd! good stuff though :)

Posted by Jerrett on November 16, 2007 at 01:26 AM PST #

Hi, Tor!

I have a question. When I start Mongrel, I see development.log in output window. In this log using some codes to colorize output. Output window doesn't support this highlighting. Will It be in future version?

Posted by Dmitry on November 17, 2007 at 01:08 AM PST #

I installed the Netbeans IDE Release candidate 1 but the ruby editor clashed. (does not display)
i had to roll back to beta 2 and miss the fun.

Please help.

George

Posted by George on November 20, 2007 at 04:52 PM PST #

Hi Tor! Thank you for your great work on this project. Your progress with refactoring, debugging and such is amazing and very much appreciated.

But there is still one problem which prevents me from switching to NetBeans for my daily development tasks - Consolas font doesnt get antialiased well.
Here i put a simple example

http://sfedu.ru/~dolzenko/consolasonnetbeans.bmp

(file is about 1.5Mb size, so i put ZIPped one too http://sfedu.ru/~dolzenko/consolasonnetbeans.zip its only 25Kb)

There is another question considering debugger features. How soon the "break on exception" feature would be added? I think its one of the crucial features for debugging.

I looked at rdebug and there is already "Debugger.catchpoint" feature you can turn on for certain exceptions.

Posted by Evegniy on November 26, 2007 at 04:28 PM PST #

Post a Comment:
Comments are closed for this entry.
About

Tor Norbye

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today