Perl プログラムで Perl プログラムを
修正する方法

Kang-min Liu // @gugod
LINE Fukuoka
YAPC Tokyo

Note:
についで紹介しています


自動修復?


PPI で
コードを
変更


PPI

Perl5 code を DOM にする

$doc = PPI::Document->new('Module.pm');

$doc->prune('PPI::Token::Comment');

$doc->save('Module.pm');

element を取得: find / find_first

# ArrarRef[ PPI::Element ] | undef
$elements = $doc->find('PPI::Token::Whitespace');

# ArrarRef[ PPI::Element ] | undef
$elements = $doc->find(sub {
  $_[1]->isa('PPI::Statement::Sub')
  && $_[1]->name eq 'hoge'
});

# PPI::Element | undef
$element = $doc->find_first(sub {
  $_[1]->isa('PPI::Token::Symbol')
  && $_[1]->content eq '$hoge'
});

Note:
find method で
pattern を指定して、 (指定: してい)
element objects として取得できます (取得: しゅとく)


削除する (remove)

if ($found = $doc->find(...)) {
  for my $elem (@$found) {
  
    $elem->remove;
  
  }
}

Note:
削除 さくじょ
method call メソッド コール


挿入する (insert_*)


$new_elem = ...; # 作る

$elem = $doc->find_first(...);
$elem->insert_before( $new_elem );
$elem->insert_after( $new_elem );

Note:
付け加える = つけくわえる
挿入 = そうにゅう


Cut + Paste

my $doc2 = PPI::Document->new(\$code_str);
my @new_elems = $doc2->children;

my $e = $doc->find_first(...);
for (@new_elems) {
    $_->remove;            # cut
    $e->insert_before($_); # paste
}

$e のまえに paste

Note:
PPI::Document::Fragement exists but
it is not really integrated with rest of PPI


Bug を捜査


$bug = $doc->find( ??? )


Perl::Critic

Critique Perl source code for best-practices.

Perl code を評価する


ProhibitStringyEval


eval "print $foo";        # not ok

eval { print $foo };      # ok


ProhibitConditionalDeclarations

my $foo = $baz if $bar;          #not ok
my $foo = $baz unless $bar;      #not ok

our   $foo = $baz for @list;     #not ok
local $foo = $baz foreach @list; #not ok

Perl::Critic::TooMuchCode

Find Dead code (ゴミコード)

  • 未使用の定数
  • 未使用の関数
  • 未使用のインポート
  • 未使用のハッシュキーや値
  • 二重定義した関数

code review は
bot がしてくれて
良いやん


reviewdog

Reviewdog を飼ってコードレビューや開発を改善しませんか


perlcritic + reviewdog

CI で code review しましょう

# .reviewdog.yml
runner:
  perlcritic:
    cmd: perlcritic --profile .perlcriticrc --verbose 1 *.psgi lib/
    errorformat:
      - "%f:%l:%c:%m"
    name: perlcritic


perlcritic + reviewdog


perlcritic + reviewdog

Docker Image: https://hub.docker.com/r/gugod/perlcritic-reviewdog

Drone CI に使用可能


bot が
修正してくれません ?


p5-nitpick

(experimental project)

https://github.com/gugod/p5-nitpick

nits (小さいゴミ) を自動的に取り除く

Note:
取り除く: とりのぞく


  • RemoveUnusedInclude 未使用 module を取り除く
  • RemoveUnusedVariables 未使用変数を取り除く
  • DedupeIncludeStatements 重複したincludeを取り除く
  • RemoveUnusedImport 未使用インポートを取り除く
  • RewriteWithAssignmentOperators

  • MoreOrLessSpaces whitespace 調整
  • QuoteSimpleStringWithSingleQuote "foo" => 'foo'
  • RemoveEffectlessUTF8Pragma
  • AppendUnimportStatement
  • RewriteHeredocAsQuotedString
  • RewriteRefWithRefUtil
  • RewriteWithAssignmentOperators

もっと 修正できる パターン

  • do_this();; semi-colons 多すぎ / empty statements.
  • ドキュメント の スペルミス
  • 変数名にスベルミス

# A
$n = scalar @arr;

# B
$n = @arr;

# A
@a = @{[ "foo", "bar", foo() ]};

# B
@a = ("foo", "bar", foo());

$bugs = $doc->find( ... )

最後

  • PPI でコードを変更することは簡単
  • ゴミコードを検出するのは面倒臭い
  • bot が code review してくれるのは楽です
  • 自動的な修復は簡単なことしかできない

ご清聴
ありがとう
ございました

Select a repo