blog

program

【Movable Typeでも複雑な処理を一元管理!】1/3
複雑な処理をスッキリ整理! グローバル・モディファイアプラグイン

CMSのテンプレートに同じ処理が何度も出てくる場合、皆さんはどうしていますか?
「コピー&ペースト」?
確かに同じ処理を行うことができますね。
でもCMSは一つの「システム」です。
「システム」が入っている以上、「システム」にやらせたいとは思いませんか?
まずはMovable Typeについて、以下のようなケースを考えてみましょう。

このリンク、かっこ悪いけど……

Movable Typeでは本来、カテゴリ、月別などのアーカイブテンプレートや個別テンプレートとその元となる記事は出力されるURLを基準にブログが指定されるべきです。
しかし、特にPowerCMSのカスタムオブジェクトなどでは、データの関連性や会員専用エリアなどの都合でURLとは違うブログに所属させたほうが都合がいい場合があります。
そのような事情でアーカイブテンプレートなどをブログURLの下ではないディレクトリに出力した場合でも、同じドメイン内であれば<$MTCategoryArchiveLink$>などでURLを出力したリンクそのままで遷移する事ができます。
しかし、出力されたHTMLのソースをみてみると……

上のディレクトリを表す「../」がそのまま出力されています。
何らかのシステムで出力されているのがバレバレじゃないですか!?
……ページの内容で分かることも多いのでこの程度であれば放置することもありますが、せっかくなのできれいに整形しましょう。

2回だけ上に出ていてそのディレクトリ名もはっきりしているのでこれぐらいで収まりますが、あまりスッキリしませんね。 メンテナンス性も悪いです。
こういうときはプラグインでグローバルモディファイアにしてしまいましょう!

プラグインは、作れる。

「プラグインなんて難しい。自分にできるわけがない」とお考えの方も多いでしょう。
しかし今回のような、グローバルモディファイアのプラグイン自体はすごく簡単です。
今回のプラグインは公式の開発者向けガイドと同じような表記だと以下のようなファイル構成になります。テスト関係は割愛しています。

$MT_DIR/
|__ plugins/
|__ RealPath/
|__ config.yaml
|__ lib/
|_ RealPath/
|__ L10N.pm
|_ L10N/
| |_ en_us.pm
| |_ ja.pm
|_ Tags.pm

$MT_DIR/」はMTをインストールしたディレクトリです。この直下に「plugins/」ディレクトリがあります。
この下に「RealPath/」ディレクトリ以下を作成します。
実際にプラグインの処理を行うPerlモジュール(PHPやjavascriptのクラスにあたるもの)の設置場所は「RealPath/lib/」以下になります。
複雑なプラグインではこの下に「MT/App/RealPath/」などができる場合もありますが、今回はすべて「RealPath/」配下のモジュールになります。

config.yaml

YAMLは構造化データをシンプルに記述するテキストデータ形式です。
プラグインの基本情報を記述します。

07行目まではMTが他のプラグインと区別する名前や、管理画面などで表示する内容になります。
「<__trans phrase=”なんとか”>」は、08行目で指定しているPerlモジュールによってMTの設定言語により変換される、多言語対応になっています。
09行目では、ここから下のインデントでタグに関する処理があることを意味しています。
10行目では、ここから下のインデントで、グローバルモディファイアを追加することを意味しています。

11行目がこのプラグインの動作を決定しています。
「:」の左側「realpath」がMTMLタグに記述するモディファイアを指定しています。
右側の「$RealPath::RealPath::Tags::_real_path」は「realpath」でこの「RealPath」プラグイン内の「RealPath::Tags」モジュール内の「_real_path」関数を実行することを意味しています。

実際に組んでみよう!

まず、お約束で「config.yaml」08行目で指定している以下のPerlモジュールを追加します。

L10N.pm

l10nは「localization(l<10文字>n)」の略です。

このファイルは「RealPath::L10N」モジュールです、という宣言です。「RealPath」はそのプラグインのディレクトリ名になります。
※直接実行しないので(できても何も起こらないはずですが)cgiファイルにあるような「#!/usr/bin/perl -w」といった行は記載しません。

ルールどおりに書かないとエラーを出力します、というおまじないです。
といっても昔のPerlが自由すぎたのであり、よほど古いコードでない限りこのルールに外れたPerlは無いはずです。
※Perlは「昔のコード」を実行できるようにするためにこの命令を追加しましたが、javascriptは逆に「古いブラウザ」でも実行できるように「文字列」として記述するようにしました。

このモジュールは「MT::Plugin::L10N」モジュールを継承しています。
必要な機能は「MT::Plugin::L10N」モジュールに全て実装してあります。
プラグインにその機能を取り込むのがこのモジュールの役割になります。

「ファイルが正常に終わりました」というおまじないです。
Perlにはtrue(真),false(偽)は概念としてはありますが、値として定義されていません。数値の1または0を使用します。もっとも、Perlは1つの変数で文字列と数値の両方を保持するので、文字列でも問題はないはずです。

en_us.pm

英語に翻訳するモジュールです。
少しずつ意味を理解していきましょう。

「RealPath::L10N」モジュールを継承しています。
その「RealPath::L10N」モジュールが「MT::Plugin::L10N」モジュールを継承しているところと同じです。

perlで「%」で始まるものはハッシュ、他の言語でいう連想配列になります(実はPHP5までの「array()」は全て連想配列です)。
ハッシュ「%Lexicon」に実際に翻訳するデータを追加します。
変数を最初に使う前に「our」をつけることでグローバル変数であることを宣言します。
多言語化する場合でも基本は英語なので、このファイルでは1行も書かないようにプラグインを作ることも可能です。
しかし、config.yamlをスッキリさせるためにこのプラグインのように作られているものが多いです。

ja.pm

日本語に翻訳するモジュールです。

3回目なのでもう分かりましたよね?
「RealPath::L10N::en_us」モジュールを継承しています。
後は英語が日本語になっている以外はen_us.pmと同じです。

UTF-8でソースファイル(コメント以外)を記述するときのおまじないです。
このモジュールだけ全角文字を使用していることに気づきましたか?
HTML側にかかわらず、PerlモジュールはUTF-8で記述してください。
そして多言語化することで、多言語化モジュール以外の文字コードを気にする必要がなくなるのです。

Tags.pm

 

関数(サブルーチン)になります。引数はここでは宣言できません。
Perlは予約語が比較的短いのも特徴の一つです。
戻り値を渡す「return」はPHPやjavascriptと同じです。

「my」をつけることでローカル変数の宣言になっています。
「use strict;」がない時代には、ローカル変数かグローバル変数かの区別をつけられず、大変なことになりました。
宣言する変数を「()」でくくると「リストコンテキスト」になります。
右側の配列の各値をそれぞれの変数で受け取る事ができます。
「@」から始まる変数が配列になります。Perlでは引数は「@_」に引数が設定されています。

本当はそこまでしなくてもいいのですが、念のため「realpath=”1″」が1以外の時には処理をしないことにします。

ここから下で実際の処理を行っています。

わかりにくいですが、少しじっくり見ていきましょう。

=~

パターンマッチ演算子。Perlの強力な検索/置換関数を使用するための演算子です。
Perlを理解するうえでもっとも重要な概念ともいえるでしょう。
といっても今はPHPでもPCREが使えますので、ほぼ同じ動作をするPHPと比較してみると分かりやすいかもしれません。
今回使用しているのは置換関数だけですが、この右側には実質3種類の関数を書くことができます。

m//

正規表現検索です。この関数がきたときは、代入ではなく比較を行います。
正規表現で検索する文字列に「/」がある場合など、「/」以外の記号で囲むこともできます。
括弧の場合は「m()」のように開き括弧と対応する閉じ括弧を使用します。
「/」が使用できる場合は「m」は省略できます。

php

perl

s///

正規表現による置換です。
こちらも「/」以外の記号を利用することもできます。
括弧の場合は「s()()」のような表記になります。

php

perl

tr///

文字単位の置換です。

php

perl

y///

「tr///」と同じです。

※4つとも、記号を置き換えた場合でも正規表現は「’」「”」でくくって文字列にしてはいけません

今回は正規表現で3回置換して、その文字列を返しています。
今回の「正規表現」の内容はPCREでも同様なので確認してみてください。
今のディレクトリをあらわす「./」や、「//」と2つ並んで残った場合も処理しているので上のテンプレートより多くなっています。

やっぱりむずかしいですか?
難しいのはMTプラグインじゃなくて、「正規表現」つまり「やろうとしている事」じゃないですか?
自分で作ろうとしている場合、「やろうとしている事」は自分が一番分かっているので、あとはPerlで記述できるかどうかだけです。

ではこのプラグインが入った環境で先ほどのテンプレートを書き換えてみましょう!

はい、モディファイア一つで同じ処理が行えるようになりました。
しかもプラグインさえコピーすればどのMovable Typeでも使えます!
今回のものは実用性は低いかも知れませんが……

※実はPerlには「Cwd」モジュールに「realpath()」関数があります。
これは同モジュールの「abs_path()」関数の別名ですが、上記と同じような処理になります。
しかも最初から入っている標準モジュールなので、確実、安全に使うことができます。

PHPにもある?
実は違います。
今回もPHPで書き直すときに違いが生じないように、正規表現で対応しました。その話はまた改めて。

2015.02.05追記
_PLUGIN_NAME,_PLUGIN_DESCRIPTIONがおかしかったのでこっそり修正。