hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

perl-refactoryっていうPerlリファクタリングするソフトウェア発見した

Perlソースコードリファクタリングするグッズ作ってる人いた.ゴミっぽいけどせっかく発見したのでシェアします.


Subversionで取ってきて読んだところ,ExtractMethodだけが実装されていた.長い処理の中の一部をメソッドに切り出したいときに使うやつ.

利用例

長いメソッド中に,こんなコード片があるのでメソッドに切り出したいということで,a.plとかに保存して,

my @foods = $shop->buy_foods($human->wallet);
for my $food (@foods) {
    $human->eat($food);
}

こんな感じに実行する.

% perl ./bin/extract < a.pl

こんなコードが出力される.$shopと$humanを引数に取るメソッドの定義と,そのメソッドの呼び出しが生成された.メソッド名はランダムにつけられる.仮引数は出現した順に決まる.これをもとのプロジェクトのコードにコピペすればリファクタリング成功.

$self->mysub_945($shop,$human);
sub mysub_945 {
  my $self = shift;
   my $shop = shift;
   my $human = shift;

my @foods = $shop->buy_foods($human->wallet);
for my $food (@foods) {
    $human->eat($food);
}

}


メソッド定義されて動いてすごいけど,実装を見るとひどい感じで,evalしてエラーをパースして変数名のリストを作ってる.

sub extract_arglist {
    my $self = shift;
    my ( $code, @args ) = @_;

    while ( !eval "$code; 1" ) {
        my $errors = IO::String->new($@);
        while ( my $item = <$errors> ) {
            if ( $item
                =~ /Global symbol "(.*)" requires explicit package name/ )
            {
                push @args, $1 unless ( grep { $1 eq $_ } @args );
            }
        }
        $code = $self->codegen( $code, 'test', @args )
    }
    return @args;
}

入力がこんなのだと$nameが見つからなくてエラーになってリファクタリング成功するのだけど,

while(1) {
    print $name;
}

こうすると普通に実行できるのでhiが無限に出る.

while(1) {
    print 'hi';
}

evalすると,eval元のスコープにもアクセスできるので,ExtractMethodsのコード自体をリファクタリングすることはできないという問題もある.

Refactory::Refactoring::ExtractMethod->extract_arglist($code);

こんなのを与えるとextract_arglistの中でまたevalするというのが繰り返されてDeep recursionになるのでリファクタリング終わらない.


無限に挨拶するとかリファクタリングが終わらないくらいで済めばいいけど,ファイルを削除するとか,副作用があるコードが含まれると良くない.気をつけて使うのも難しいので,このツールは使うべきではない.
メソッド切り出しリファクタリングは危険ということではなくて,このツールの実装方法がよくなくて,とりあえず実行してみるんじゃなくて,ASTを解析してメソッドに切り出すべきだと思う.
1コミットで終わってるし,作りかけで打ち棄てられているようだった.
Perlリファクタリンググッズでいいの知ってる人いたら教えてください.