Perl での動的関数呼び出し

 Windows AzurePerl での REST API を紹介するためのサンプルとして掲示板でも作ろうかと思ったのですが、なんというか、見込みの甘さに嵌りました。


 世に出ている掲示CGIのコードが汚い。

 まぁ、難読化ツールを使っているのでしょうけど、use strict; を追加するだけで溢れるエラーの数々に、データ部を差し替えてやればいいや、とか思っていた見込みを放り投げて、一から作ってます(w

 で、溢れるグローバル変数は論外として(なんでこんなコードが世に溢れているのか理解しがたい)、次に気になったのが、フォームのコマンド文字列によって if 〜 elsif 〜 else がだらだらと続くコード。
 コマンド・パターンか何かで簡単に書けないかとちょっと漁りました。
 パッケージで関数名が取れるじゃないですか。あとはこれと eval を組み合わせれば、簡単にコマンド化できますよね。

 やってみました。

 まずは、コマンド群となる関数を保持するモジュール Functor.pm を作成します。

# Functor.pm

package Functor;

sub callee
{
    my $param  = shift if @_;

    if ( defined($param) )
    {
        print "Hello, $param->{name}!\n";
    }
    else
    {
        print "Hello, world!\n";
    }
}

1;

 次に実行関数を記述します。

# Test.pl

use strict;
use warnings;

use Functor;

package main;

# Hello, world! を出力
&dispatcher('callee');

# Hello, Perl! を出力
&dispatcher('callee', { name => 'Perl', } );

0;

sub dispatcher
{
    my $callee = shift;
    my $param  = shift;

    my $func   = sprintf("*Functor::%s", $callee);
    my $enable = 0;
    foreach ( values %Functor:: )
    {
        if ( $_ eq $func )
        {
            $enable = 1;
            last;
        }
    }
    $enable or die "Illeagal function called.\n";

    my $call = sprintf('&%s', $callee);
    $call .= '($param)' if defined($param);
    return eval "$call;";
}

1;

 このTest.plを実行すると、Functor パッケージ内の指定関数が検索され、(もしあれば、$param を引数に)eval 関数で実行されます。

 これで新規機能を追加するときも、メインのコードを修正することなく、Functor 中の関数を増やすだけで対応できます。
 オブジェクトに組み込むのも簡単ですから、いろいろと使い勝手が良さそうです。