エンジニアブログ

エンジニアブログ
Perl

perl-5.10のperl機能を排除し、Mojoliciousをperl-5.8.7で動くよう改造したmojo-legacyのv3.54

8c280f4554be533e4c1d3b0b489bbb0c-1.jpeg sugama 2012年11月07日

こんにちは。須釜です。

つい先日、mojo-legacyの最新版をgithubにアップしたので、今日はその作業内容を通じて、mojo-legacyをご紹介します。

mojo-legacyはMojoliciousをperl-5.8.7環境でも動くように改造したものです。どんな改造か一言で言うと、主にperl-5.10のperlの機能を排除しています。

もう少し具体的に言うと、主に下記のようなことをしており、ほとんどが単調な手作業です。perl-5.10以降では正規表現をはじめ、多くの変更点があるようですが、幸い、Mojoliciousでは下記以外には非互換な機能は使っていないようです。

  • defined-or演算子を書き換え
  • スマートマッチを書き換え
  • stateをourに書き換え
  • sayをMojo::Baseで提供
  • reモジュールをMojoLegacy::reに差し替え
  • 最新のGetopt::Longをバンドル(new)
  • その他の小細工

defined-orはperl-5.10から導入された演算子ですので、それ以前のperlでは使えません。

my $value = $self->value // '';

perl-5.8系で等価なコードは下記のようになります。

my $value = defined $self->value ? $self->value : '';

//=も

$self->{raw_size} += length($chunk //= '');

同様に、下記のように書き換え可能です。

$self->{raw_size} += length($chunk = defined $chunk ? $chunk : '');

下記のようなコードは書き換えづらいですが

$self->{buffer} .= shift // '';

doブロックで一時変数を使って凌いでいます。

$self->{buffer} .= do {my $buffer = shift; defined $buffer ? $buffer : ''};

次にスマートマッチです。最近のMojoliciousは、将来、スマートマッチの仕様が変更されるのに配慮して、あまり使わない方針にしたようですが、まだ下記のようなコードが残ってます。

return $self->new(grep { $_ ~~ $cb } @$self);

これは、たぶん下記のようなコードが等価になると思います。長くなってイヤなのですが、もっといい書き方があるでしょうか。

if ((ref $cb) eq 'CODE') {
    return $self->new(grep { $cb->($_) } @$self);
} else {
    return $self->new(grep { $_ =~ $cb } @$self);
}

state変数は

sub singleton { state $loop ||= shift->SUPER::new }

ourで代用しています。

our $singleton_loop;
sub singleton { $singleton_loop ||= shift->SUPER::new }

実際の変更点は、私の作業用のリポジトリのdiffを見て頂くと分かります。

mojo-legacyのv3.54からは、テストのためにTest::Moreをアップグレードする必要があります。また、morboを使用するためにはSocketもアップグレードする必要がありそうです。非コアモジュールに依存してしまいますが、これは開発環境のお話なので、出来上がったアプリをperl-5.8.7にデプロイするだけであれば、アップグレードの必要はありません。

cpanm Test::More
cpanm Socket

なお、今回からGetopt::Longもバージョン依存になってしまったのですが、こちらは本番環境でも使われるため、バンドルしました。

レガシーな環境に何かを移植する際の参考に(?)なれば幸いです。

ご意見・参考などお待ちしています!