Hmm... this is easier/harder than expected

pdcawley on 2001-11-01T11:33:16

So, if you read my article about why I think Perl 6 is cool, you'll remember that I mentioned that I thought Perl 6 would make it easier to write a Refactoring Browser for Perl. (See http://www.refactoring.com/ for a discussion of what refactoring is, and for pointers to the 'original' refactoring browser)

Within the refactoring community there is the idea of a 'Rubicon' for a 'real' refactoring browser. If your tool can successfully do the 'extract method' refactoring (where a section of code is selected by the user and the browser goes away and turns that into a new method and replaces the selection with an appropriate call to that method, possibly interrogating the user for more information in the process) then it should all be down hill from there...

Anyway. Soon after the article went live, James of this parish pointed out a trick on the london.pm mailing list that got me thinking about how to do 'extract method' in Perl 5. James' trick got me a good long way along the road, and a few steals from B::Deparse and uninit.pm (an unreleased module by Simon Cozens, nag him) and I reached the point where I could do:

my $refactory = Devel::Refactor->new; my $md = $refactory->extract_method('method_name', 'package' 'print $lex; print');

And then have C<$md->as_string> return

sub method_name { my $self = shift; my $lex = shift; local $_ = shift;

print $lex; print }

Yeah, the layout is funny. And also C<$md->call_string> would return:

$self->method_name($lex, $_);

Which is quite good. As it stands at the moment you can also pass lexical hashes and arrays too. We also respect fully specified global variables C<$pkg::foo> and don't try and pass them as arguments. And life is very good.

However, we lack the context that the eventual method will be compiled in, so we can't see C or type globals and we try to make them into parameters. Nor can we see any package lexicals, which could be annoying.

But if we're going to actually do the replacements and stuff we're going to need to know whereabouts in the perl module we should stick the new method defintion (it's not quite as simple as just bunging it on the end) which means that we need to do some introspection on the module file, and all of a sudden I'm doing bad things with perldebguts, Safe, and probably other stuff before I'm done.

I have the feeling that a full blooded class browser for perl is almost going to 'fall out' of this project.

Anyway, if you want to see what I've done so far, take a look at http://sourceforge.net/projects/preface and pull the latest version out of CVS. If you want to run the tests you're also going to need a copy of the bleading edge version of PerlUnit, which is available from http://prdownloads.sourcforge.net/perlunit/Test-Unit-PDC_REFACTOR.tar.gz

Enjoy. Patches and docs welcome...

BTW, PREFACE is a tortured acronym for Perl REFACtoring Engine. Blame Greg McCarroll.