私が歌川です

@utgwkk が書いている

perlcriticのポリシー書いた

perlcriticとは

perlcriticとは、Perlのlinterです。JavaScriptで言うところのESLintみたいな感じで、Perlのソースコードを解析して、バグを招きかねない・ポリシーに合致しないコードがあれば警告をしてくれます。

perlcritic本体にさまざまなポリシーが含まれており、設定なしでも使うことができるようになっています。また、ESLintと同様に、特定のパターンに一致するコードがあれば警告するようなポリシーを自分で作ることができます。

作ったポリシー

Perl::Critic::Policy::ProhibitOrReturn

Perl::Critic::Policy::ProhibitOrReturn - Do not use `or return` - metacpan.org

以下のように ... or return でearly returnをする書き方をしたら怒る、というポリシーです。ぼくはこの書き方があまり好きではなく return ... unless ... のように書くべきだと思っています。perlcritic本体のコードでもよく使われているので、よくあるイディオムなのかもしれないけどどうにも受け入れがたい、ということでポリシーにしました。

sub func {
    my ($x) = @_;
    $x->{hoge} or return; # not ok

    ...;
}

Perl::Critic::Policy::BuiltinFunctions::ProhibitReturnOr というポリシーがありますが別物です。

Perl::Critic::Policy::ControlStructures::ProhibitReturnInDoBlock

Perl::Critic::Policy::ControlStructures::ProhibitReturnInDoBlock - Do not "return" in "do" block - metacpan.org

以下のように do ブロック内で return していたら怒る、というポリシーです。

sub func {
    my ($x) = @_;
    my $y = do {
        return unless $x; # not ok
        my $z = ...;

        ...;
    };

    ...;
}

変数宣言と同時に値を初期化したいけど、そのために一時変数を作りたくない、というときに do ブロックを使うことでスコープを汚さずに書くことができます。 このとき do ブロック内でearly returnしたくなって、ぼやっとしてるとこういう書き方をしてしまいます。このように書くと、 do ブロックではなく func サブルーチンからreturnしてしまい、混乱を招くことになります。early returnしなくなったら do ブロックの内部をサブルーチンに分けるべきでしょう。

困りごと

同じようなポリシーが既にないか探すのが難しい

metacpanでがんばって検索することになるけど、ポリシー単体で1つのdistributionになっていたり、ポリシーバンドルに含まれていたりするので、結局distributionを全部見ないと見落しがある気がします。

ポリシーバンドルについてはScrapboxにまとめてなんとかしようとしていますが、手でやってるのでこれも抜け漏れがありそう & 新しいdistributionが出たら探しに行かないといけない ということで結局難しい。metacpanがAPIを提供している*1ことを知ってから多少はましになったかもしれません。

ポリシーの名前空間をどうするかが難しい

  • Perl::Critic::Policy::ProhibitOrReturn のように、何をどうするか という名前にする
    • 単純明快
  • Perl::Critic::Policy::ControlStructures::ProhibitReturnInDoBlock のように、ポリシーの分類・何をどうするか という名前にする
    • 間違った分類名にしてしまうと気まずい
      • 迷ったらPrePANで見てもらうとよい?
      • すでに Perl::Critic::Policy::BuiltinFunctions::ProhibitReturnInDoBlock という名前にしたほうがよかったかもと思ってきている……
    • 分類名どうするか決めるのが難しいパターンがありそう
  • Perl::Critic::Policy::UTGWKK::Hoge のように、誰が作った・何をどうするか という名前にする??
    • ポリシーの分類も含められる
    • ぼくが作ったこういうポリシーです、という名前になってて、ちょっと主張が強い気がする
      • ポリシーのバンドルみたいなのを作るときには、どのバンドル由来か分かって便利そう

ポリシーのdistribution単位をどうするか

  • ポリシーごとに1 distributionにする
    • ポリシー単体でインストールできる
  • ポリシーバンドルを1 distributionにして、バンドル内にポリシーを追加していく
    • ポリシー単体でインストールできなさそう
      • バンドル内に相容れないポリシーがあったら都度無効化する必要がある
    • 最初からバンドルとして作っていく、という気持ちがない場合はこうしない気がする
  • ポリシーごとに1 distributionにして、ポリシーバンドルのdistributionを入れるとポリシーが複数入るかたちにする
    • 上2つの複合形
    • ポリシー単体で入れたい、というのとバンドルを入れたい、というのを両立できる

perlcriticやってる友だちを知らない

発表や意見交換をする機会がなくて、知見は集まってきたけど他に困ってる人いないのか・なにか知ってる人はいないのか などとくに分からない状態でやっています。

Perlアドベントカレンダー参加します

Perl Advent Calendar 2020 - Qiita に参加します。perlcriticネタがけっこう集まってきたのでひとつ書こうと思っていますが、別のネタが出てきたらそっちにシフトするかもしれません。

*1:なんとElasticsearchのクエリを直接投げることができる!!!!