Under the Bridge

a Picture of the Late Him

MT4:MTの変数演算をプラグインで拡張

2008年4月20日 22:29 | Writer: yoshi | 記事本文 | コメント(0) | トラックバック(0)

Movable Type4.1以降でよく使用するようになった、変数での演算。この前、乱数が用いたいと思ったんだが、標準のテンプレートタグではできない。JavaScriptでやるにしても、それはクライアントコンピュータ側での処理となり、テンプレートの処理分岐などには使えない。

これを拡張するプラグインを試作してみた。標準のMTSetVarテンプレートタグにop="+"などというモデファイアを付与する標準の方式では、計算時の左辺がnameモデファイア、右辺がvalueモデファイアとなるので、慣れていない方へは直感的にわかりづらい(と思う)し、記述のやり方が(例えば単に乱数や三角関数の結果が欲しいときなどは)面倒くさい。

Movable Type4.1以降で動作する(他の環境ではチェックしていない)。

プラグインソース

以下参照。

package MT::Plugin::CalcExp;
use strict;
use MT;
use MT::Plugin;
use base qw(MT::Plugin);
use POSIX;

my $plugin = new MT::Plugin::CalcExp({
    id => "CalcExp",
    key => "CalcExp",
    name => "CalcExp",
    version => '0.1',
    description => "<MT_TRANS phrase=\"The Calculation Value(Expand) \">",
    author_name => "apstar",
    author_link => "http://www.mtde.info/",
});
MT->add_plugin($plugin);

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

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) || ('join' eq $op)) {
        return $base . $palam;
    }
    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;
}

1;

使い方

計算の種類がopモデファイア、元の値がbaseモデファイア、計算用のいじくりパラメータがpalamモデファイアとなる。例えば、乱数がほしいときはbaseが100、palamが10、opが"rand"であれば90-110の範囲で値を返す。

palamパラメータが必要ないものもある。整数丸めとか。それはopモデファイア(int)とbaseモデファイア(12.3456など)のみを渡せばよく、palamモデファイアは不要。

モデファイアについてドキュメントなど書きたいが、いまのとこそういうものはない。

参考になるかどうかアレだが、コードは以下参照。

(足し算)
<MTSetvar name="value1" value="111">
<MTSetvar name="value2" value="21">
<MTCalcExp base="$value1" palam="$value2" op="+">
<br />

(引き算)
<MTSetvar name="value1" value="111">
<MTSetvar name="value2" value="21">
<MTCalcExp base="$value1" palam="$value2" op="-">
<br />

(掛け算)
<MTSetvar name="value1" value="111">
<MTSetvar name="value2" value="21">
<MTCalcExp base="$value1" palam="$value2" op="*">
<br />

(割り算)
<MTSetvar name="value1" value="111">
<MTSetvar name="value2" value="21">
<MTCalcExp base="$value1" palam="$value2" op="/">
<br />

(余剰)
<MTSetvar name="value1" value="111">
<MTSetvar name="value2" value="21">
<MTCalcExp base="$value1" palam="$value2" op="%">
<br />

(文字列連結)
<MTSetvar name="value1" value="週間">
<MTSetvar name="value2" value="秩父伝説">
<MTCalcExp base="$value1" palam="$value2" op="join">
<br />

(乱数)
<MTSetvar name="value1" value="0">
<MTSetvar name="value2" value="100">
<MTCalcExp base="$value1" palam="$value2" op="rand">
<br />

(ゼロ埋め)
<MTSetvar name="value1" value="71">
<MTSetvar name="value2" value="4">
<MTCalcExp base="$value1" palam="$value2" op="zero">
<br />

(四捨五入)
<MTSetvar name="value1" value="123.456789">
<MTSetvar name="value2" value="3">
<MTCalcExp base="$value1" palam="$value2" op="round">
<br />

(整数化)
<MTSetvar name="value1" value="123.456789">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="int">
<br />

(切り捨て)
<MTSetvar name="value1" value="123.456789">
<MTSetvar name="value2" value="5">
<MTCalcExp base="$value1" palam="$value2" op="floor">
<br />

(切り上げ)
<MTSetvar name="value1" value="123.456789">
<MTSetvar name="value2" value="5">
<MTCalcExp base="$value1" palam="$value2" op="ceil">
<br />

(べき乗)
<MTSetvar name="value1" value="2">
<MTSetvar name="value2" value="16">
<MTCalcExp base="$value1" palam="$value2" op="pow">
<br />

(平方根)
<MTSetvar name="value1" value="144">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="sqrt">
<br />

(sin)
<MTSetvar name="value1" value="30">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="sin">
<br />

(cos)
<MTSetvar name="value1" value="30">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="cos">
<br />

(tan)
<MTSetvar name="value1" value="30">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="tan">
<br />

(角度→rad)
<MTSetvar name="value1" value="30">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="angle2rad">
<br />

(rad→角度)
<MTSetvar name="value1" value="0.789">
<MTSetvar name="value2" value="">
<MTCalcExp base="$value1" palam="$value2" op="rad2angle">
<br />

特記事項

参考にしたのはこちら。

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

# 今の私にはヨダレもんの記事が盛りだくさんで、最近はちょくちょくお邪魔しています。クオリティの高い記事をありがとうございます。

ほか、プラグインを作るために必要になりそうな知識を公開しているサイトをチョコチョコ訪問した。今回作成したのは簡単な練習のためのファンクションタグなので、MTの中の中まで調べることはやっていない。

それと、MT4の/lib/MT/Template内のContextHandlers.pmの8500行目辺り以降に_math_operation関数があるので、そちらが参考になる。

このプラグインは自分で使用する前提であるので、拡張性を持たせたい。まず、使いそうな関数を初めから準備した。Asset画像を拡大・縮小した際の数値の丸め。四捨五入・切捨て・切り上げなどがいるかと思い、初めから実装している。これはperlの標準命令でもいけるんだが、切捨てと切り上げはperlのPOSIXモジュールという便利ライブラリ内に関数が(floor、ceilですな)あったので、それを利用している。将来的にPOSIXから使用したい関数が出てきたとき、最初からプラグインに実装しておくと有利かな...などと考えた。

あと私は、三角関数や角度→ラジアン演算なんかは本職ではよくやるのだ。一応つけてみた。スタイルシートの何かを三角関数を用いて計算...することは、今のところは、...ないだろうけど。

トラックバック(0)

このブログ記事を参照しているブログ一覧: MT4:MTの変数演算をプラグインで拡張

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

コメントする






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

parts

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

あわせて読みたい

なかのひと

2008 yoshi(apstar)