hitode909の日記

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

Perlリファクタリングツール作ってる

こんにちは,まずはこのGIFをご覧ください.



Perlのソースコードをリファクタリングするツールまともなのがないから自作することにした.perl-refactoring-toolsっていうそのままの名前.

いろいろあってApp::PRTになった


いまのところ,トークンの置き換えと,クラスのリネームができる.
テストのカバレッジ100%で意識高い.

トークンの置き換え

トークンの置き換える例.newというトークンをatarasiiというトークンに置き換えてみる.->newってなってたのが,->atarasiiになる.
トークンが一致したら置き換わるので,newsは置き換わらなくて,newだけ置き換わる.
型推論とかないので,どのクラスのnewだけ,みたいな指定はできない.

% ../perl-refactoring-tools/bin/prt replace_token new atarasii lib/**/**.pm
% git diff
diff --git a/lib/HTTP/Message/PSGI.pm b/lib/HTTP/Message/PSGI.pm
index 131fe26..26c6601 100644
--- a/lib/HTTP/Message/PSGI.pm
+++ b/lib/HTTP/Message/PSGI.pm
@@ -32,10 +32,10 @@ sub req_to_psgi {
     my $content = $req->content;
     if (ref $content eq 'CODE') {
         if (defined $req->content_length) {
-            $input = HTTP::Message::PSGI::ChunkedInput->new($content);
+            $input = HTTP::Message::PSGI::ChunkedInput->atarasii($content);
         } else {
             $req->header("Transfer-Encoding" => "chunked");
-            $input = HTTP::Message::PSGI::ChunkedInput->new($content, 1);
+            $input = HTTP::Message::PSGI::ChunkedInput->atarasii($content, 1);
         }

クラスのリネーム

クラスのリネーム.Plack::RequestをPlack::Kudasaiにしてみる.
Request.pmが消えてKudasai.pmができる.

% ../perl-refactoring-tools/bin/prt rename_class Plack::Request Plack::Kudasai lib/**/**.pm
% git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   lib/Plack/App/Directory.pm
#       deleted:    lib/Plack/Request.pm
#       modified:   lib/Plack/Test/Suite.pm
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       lib/Plack/Kudasai.pm


Kudasai.pm見るとちゃんとpackageの宣言が変わってる.

% head lib/Plack/Kudasai.pm
package Plack::Kudasai;
use strict;
use warnings;
use 5.008_001;
our $VERSION = '1.0029';


Plack::Requestを利用する側のクラスも書き変わってる.

--- a/lib/Plack/App/Directory.pm
+++ b/lib/Plack/App/Directory.pm
@@ -7,7 +7,7 @@ use HTTP::Date;
 use Plack::MIME;
 use DirHandle;
 use URI::Escape;
-use Plack::Request;
+use Plack::Kudasai;

 # Stolen from rack/directory.rb
 my $dir_file = "<tr><td class='name'><a href='%s'>%s</a></td><td class='size'>%s</td><td class='type'>%s</td><td class='mtime'>%s</td></tr>";
@@ -45,7 +45,7 @@ sub should_handle {

 sub return_dir_redirect {
     my ($self, $env) = @_;
-    my $uri = Plack::Request->new($env)->uri;
+    my $uri = Plack::Kudasai->new($env)->uri;
     return [ 301,


該当箇所はなかったけど,use parentしてPlack::Requestを継承して使ってるクラスも書き変わるようになってる.

日記

Perl用のまともなリファクタリングツールがないのは困っていて,前からちょっと調べたりしてた.けど本当にろくなのなさそうだった.

IDEとかあれば1クリックでできるのを,いろんなファイルを手で行き来してちまちま書き換えているのはつらい.


前に,トークンの置き換えるスクリプトとか,statement単位で置き換えるのとか,いろいろ作ってた.

こういうスクリプトを毎回ぱらぱら書くのはだるいので,なんかプロジェクトとしてまとまってるべきだと思った.perl-refactoring-toolsは,prt replace_token みたいに,サブコマンドで何をするか渡す.操作はCommand以下のクラスに実装されていて,テストも書けるようになってる.
クラスのリネームのコマンドの実装とそのテスト.

ありとあらゆる操作がこのプロジェクトのCommandに実装されていて,呼べば動く,という形になるのを目指したい.


慣れてるからPPIでパースしてるけど,Compiler::Lexerのほうが速そうなので,そのうち変えるとよいかもしれない.
あと,../perl-refactoring-tools/bin/prtとかして実行するのがださい.あとディレクトリがちがうとcarton execできない気がする.まだ困ってないけどそのうち分かったらなんとかしたい.


簡単な操作しかないけど,いちおう動くようにはなっていて,仕事でも使ってる.仕事で使ったら,親クラスリネームしても子クラスは書き換えてくれないことに気付いて,さっき継承も見るようにした.
リネームのコストが減るのは良いことで,これまでは,あとから変えるの大変だから熟慮の末名前を決めてたけど,あとからコマンド1つで安全に変えられることになれば,まずは気軽に名前で作り初めて,あとから,実はこの名前のほうがよかった,とか変えられるので,精神的な負担が減る.
暇な人いたら開発に参加すると,Perlのまともなリファクタリングツールができてうれしいと思う.