Under the Bridge

a Picture of the Late Him

MT4.1:MTの計算機能を拡張するプラグイン(CalcExp)開発の話

2008年5月 6日 12:09 | Writer: yoshi | 記事本文 | コメント(0) | トラックバック(0)

MTの計算機能を拡張するプラグイン(CalcExp)開発のときの話を書いておきます。

誰かの何かの参考になれば。また、自分のメモのためにも。

作った経緯

mixiの変態コミュで、3のつく時にアホになり、5がつくときに犬っぽくなるコードを書くとき、アホ具合と犬具合をランダムに切り替えると面白いかな?と。アホデータと犬データを配列で準備しておき、乱数を用いてそれを配列の要素とすれば簡単なのですが...MTで乱数って取得できない。

よく見るサイト、Open MagicVox.net さんとこにそういうプラグインがあるのは知っていました。

変数操作を無駄に拡張するMovableTypeプラグイン:MathOperatorExpander

あと、MTプラグインでは有名な The blog of H.Fujimoto さんも作成されています。

変数の機能を拡張するプラグイン

パクろうと思えばできなくもないですが、勉強のため、自分で後々拡張する可能性もあるので、イチから自分で書いてみた次第です。

プラグインコード

※日本語化の部分は掲載していません。

package MT::Plugin::CalcExp;
use strict;
use MT;
use MT::Template::Context;
use base qw(MT::Plugin);
use POSIX;
use List::Util qw(sum);
use List::Util qw(max);
use List::Util qw(min);
use vars qw($PLUGIN_NAME $VERSION);
$PLUGIN_NAME = 'CalcExp';
$VERSION = '0.3';

my $plugin = new MT::Plugin::CalcExp({
    id => 'CalcExp',
    key => 'calc_exp',
    name => 'CalcExp',
    version => $VERSION,
    description => '<__TRANS phrase="Calculation Value Expander Plugin">',
    author_name => 'apstar',
    author_link => 'http://www.mtde.info/',
    l10n_class => 'CalcExp::L10N',
});

MT->add_plugin($plugin);

sub init_registry {
    my $plugin = shift;
    $plugin->registry({
        tags => {
            function => {
                'CalcExp' => \&_hdlr_getvalue,
                'CalcExpArray' => \&_hdlr_getvalue_array,
            },
        },
    });
}

sub _hdlr_getvalue {
    my($ctx, $args) = @_;
    my $op = $args->{op};
    my $base = $args->{base};
    my $palam = $args->{palam};
    use constant PI => 3.14159265358979;
    
    if (('+' eq $op) || ('add' eq $op)) {
        return $base + $palam if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('-' eq $op) || ('sub' eq $op)) {
        return $base - $palam if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('*' eq $op) || ('mul' eq $op)) {
        return $base * $palam if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('/' eq $op) || ('div' eq $op)) {
        return $base / $palam if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('%' eq $op) || ('mod' eq $op)) {
        # Perl % is integer only
        $base = int($base);
        $palam = int($palam);
        return $ctx->error(MT->translate('Division by zero.'))
            if $palam == 0;
        return $base % $palam  if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('++' eq $op) || ('inc' eq $op)) {
        return ++$base if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('--' eq $op) || ('dec' eq $op)) {
        return --$base  if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif (('&' eq $op) || ('append' eq $op)) {
        return $base . $palam;
    }
    elsif (('&' eq $op) || ('prepend' eq $op)) {
        return $palam . $base;
    }
    elsif ('zero' eq $op) {
        return sprintf("%0".$palam."d", $base);
    }
    elsif ('rand' eq $op)  {
        return $base + int(rand($palam))+1 if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('int' eq $op) {
        return int($base) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('round' eq $op) {
        return round($base, $palam) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('floor' eq $op) {
        return floor($base) if defined $base && $base =~ m/^\-?[\d\.]+$/; #by POSIX
    }
    elsif ('ceil' eq $op) {
        return ceil($base) if defined $base && $base =~ m/^\-?[\d\.]+$/; #by POSIX
    }
    elsif ('sin' eq $op) {
        return sin($base) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('cos' eq $op) {
        return cos($base) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('tan' eq $op) {
        return sin($base)/cos($base) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('deg2rad' eq $op) {
        return ($base / 180) * PI if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('rad2deg' eq $op) {
        return ($base / PI) * 180 if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('log' eq $op) {
        return log($base) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('pow' eq $op) {
        return ($base ** $palam) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }
    elsif ('sqrt' eq $op) {
        return sqrt($base) if defined $base && $base =~ m/^\-?[\d\.]+$/;
    }

    return $base;
}

sub round {
    my $val = shift;
    my $col = shift;
    my $r = 10 ** $col;
    my $a = ($val > 0) ? 0.5 : -0.5;
    return int($val * $r + $a) / $r;
}

sub _hdlr_getvalue_array {
    my($ctx, $args) = @_;
    my $op = $args->{op};
    my $palam = $args->{palam};
    my @palamlist = split( /,/ , $palam );
    
    if ('avg' eq $op) {
        my $sum = sum @palamlist;
        my $num = @palamlist;
        my $avg = $sum / $num if defined $palam && $num >0;
        return $avg;
    }
    elsif ('max' eq $op) {
        my $max = max @palamlist;
        return $max;
    }
    elsif ('min' eq $op) {
        my $min = min @palamlist;
        return $min;
    }
}

1;

特徴

出来合いのperlモジュールを幾つか使用しています。計算系の拡張モジュールです。いわゆるライブラリ的なもので、例えば、私が複雑な演算のコードを書くよりは格段にエラー発生の確率が低く、汎用性に優れています。

私は本職でプログラムも触るので、ライブラリを利用して楽をしなければいけない(できれば...ではなく、やれ!Must!です)という感覚が強いです。車輪の再開発、みたいなことが嫌いです。しかし世の中にない車輪の開発は好きです。

話がそれた...このあたりです。

use POSIX;
use List::Util qw(sum);
use List::Util qw(max);
use List::Util qw(min);

あと、プラグインの拡張はとても簡単そうな感じとなりました。

使途

もともとMTのテンプレートタグで変数を用いた演算を行おうとすると、かなりコードが長くなってしまう場合があります。とくに繰り返し演算が必要になるときに威力を発揮しそうです。

mtde.info縦横比を保持して全ての画像の幅をそろえる」こんな簡単なことをやるのにありえないコードの長さ。こういうのが改善されそうです。

ほか、思いつく使途は、「CSSにおけるpaddingの自動演算」、「一日辺り何件の記事をポストしているか平均値計算」、「一番コメント数・トラックバック数が多い記事を全エントリよりピックアップ」、「画像ファイルの平均ファイル容量を計算」などなど。

資料とか

このようなプラグインを作る場合、MTソースを見るといいと思います。MTのlib\MT\Templateフォルダ内に、ContextHandlers.pmというファイルがあります。その8500行目辺り以降に、_math_operationという関数があります。そこが参考になります。

型ができてしまえば、後は拡張するだけ。必要なのは、perlのコードを書く知識となります。

私は、Perl表技集とほほのperl入門 あたりをよく参考にします、今のところ。

先日リャマ本も買いましたが、買った日にナナメ読みしただけで、あまり読まないです。

トラックバック(0)

このブログ記事を参照しているブログ一覧: MT4.1:MTの計算機能を拡張するプラグイン(CalcExp)開発の話

このブログ記事に対するトラックバックURL:

コメントする






Categories
Entries
Feed
スポンサードリンク

parts

フィードメーター - Under the Bridge

あわせて読みたい

なかのひと

2008 yoshi(apstar)