その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

Test::Synopsis にpull-request を送りました

Miyagawa さんが作成・メンテナンスをされているTest::Synopsis にpull-request を送りました。
miyagawa/test-synopsis · GitHub

Namba.pm #0 のエントリ でちょろっと触れた内容です。
実際、スライドの内容そのままな感じもありますが……

Test::Synopsis

モジュールファイル中に記述されているSYNOPSIS の構文をチェックしてくれるという大変クールなモジュールです。
詳しくは、id:gfx氏のエントリである
Test::Synopsis - Islands in the byte stream
等を参照下さい。

動作としては、POD 中の“=head1 SYNOPSIS”から次の“=head1”まで記述されている内容を正規表現でガバッと持ってきて、*1
それをeval で評価して構文チェックを行っているようです。

ここで問題

拙作のStatistics::PhaseOnlyCorrelation みたいな感じでSYNOPSIS を書くと、Test::Synopsis がコケます。
原因は先ほど述べたように、“=head1 SYNOPSIS”から次の“=head1”まで記述されている内容をPerl のコードとして扱う為です。

SYNOPSIS セクション中にコードではなくコメントを記述したい場合でも*2、Test::Synopsis はそれをPerl のコードとして扱います。
その為、通常はテストがコケます。*3
また、1つのSYNOPSIS セクションに複数個のコードチップを掲載する場合も同様の理由でテストがコケてしまいます。

なので

そこら辺を解決したパッチをpull-request として送りました。

具体的に何をしたかと言うと、
  • “=for test_synopsis_comment_begin”と“=for test_synopsis_comment_end”でくくった部分をコメントとして扱う (つまりeval の評価対象から外す) ことにした
  • SYNOPSIS セクション中に、インデントを入れずに記述された文が存在する場合はそれもコメントとして扱うことにした
  • “=for test_synopsis_divide”をSYNOPSIS セクション中に記述すると、その部分でSYNOPSIS を分割してそれぞれ独立したコードとして扱うことにした

チキショー! 日本語難しい!!!

つまり、
=head1 SYNOPSIS

    use strict;
    use warnings;

    my $foo = "bar";

THIS IS A COMMENT

    use strict;
    use warnings;

    my $foo = "baz";
というテストがコケるSYNOPSIS を、以下のように書き換えればテストが通るように改造したのです。
=head1 SYNOPSIS

    use strict;
    use warnings;

    my $foo = "bar";

=for test_synopsis_comment_begin

THIS IS A COMMENT

=for test_synopsis_comment_end
=for test_synopsis_divide

    use strict;
    use warnings;

    my $foo = "baz";
あるいは
=head1 SYNOPSIS

    use strict;
    use warnings;

    my $foo = "bar";

THIS IS A COMMENT
=for test_synopsis_divide

    use strict;
    use warnings;

    my $foo = "baz";
こうすると、Test::Synopsis は“THIS IS A COMMENT”をコメントとして扱い、
更に、
    use strict;
    use warnings;

    my $foo = "bar";
    use strict;
    use warnings;

    my $foo = "baz";
という風に2つのコードに分割して、それぞれを個別に評価します。

そんな感じです。ただ……

誰得……というか僕得なパッチなので、多分pull-request は採択されないでしょう!!!
野良モジュールとして頑張れ!!

*1:my $code = ($content =~ m/^=head1\s+SYNOPSIS(.+?)^=head1/ms)[0];

*2:上記モジュールにおける“Or if you want to use own FFT function, you may use like so:”みたいな感じで

*3:「通常は」と書いたのは、例えば“$hoge = "fuga";”のようにPerl コードのようなコメントを書いた場合はテストがコケないからです