Feb 26, 2009

MTテンプレートのアトリビュートをモディファイアと呼ぶのは止めちまえ

ちょっと前から気になっていたことなのだが、MTテンプレートタグのアトリビュートないしオプションを「モディファイア」と呼ぶのは、最近始まった悪しき慣習だ。

テンプレートタグリファレンス | MovableType.jp

そもそもアトリビュート(オプション)とモディファイアでは言葉の「クラス」が異なる。

アトリビュート(オプション)は、そのファンクションの振る舞いを制御するための情報を与える手段であろう。それに対して、モディファイアはアトリビュートの一サブクラスであって、ファンクションの出力への修飾(フィルタの適用)を指示するものであろう。

確かにmt:Entriesにlastnを指定したとき、「mt:Entriesに最新のN件を取り出すように指示」しても「mt:Entriesが生成した全リストから最新のN件をフィルタして出力」しても同じ結果が得られるのだからどちらでも構わないという見解は理解できる。だが、実際にやっているのは前者であり、glueのような反例(フィルタではないアトリビュート)もすぐ見つかる。glueでは分かりにくければ、アトリビュートに計算式を与えると計算してくれるファンクションタグを想定すればよい。

シックス・アパート担当者の意図は、説明に使う術語を減らした方が分かりやすいだろうというところにあるのだと思う。そうした事情は理解できる。でもだとしたらモディファイアなどという特殊な術語を場当たり的に使わなくてもいいはずで、全部アトリビュートと呼べばいい。実際、英語版のページを見ると、「グローバル・モディファイア」のことをtemplate tag modifierあるいは単にmodifier、「(アトリビュートとしての)モディファイア」のことをattributeと呼んでいるようだ。

MTテンプレートのアトリビュートをモディファイアと呼ぶのは止めちまえ。

Feb 25, 2009

ダイナミックパブリッシングでsort_methodを使えるようにするパッチ

ダイナミックパブリッシング時には、MTSubCategoriesMTTopLevelCategoriesなどでsort_methodオプションが無視されてしまいます。この問題を解決するパッチを作りました。sockfish用ですが、MT 4.23などにもそのまま適用できると思います。

mtos-r3457-sort_method-php-support.patch

sort_methodには"FooClass::barMethod"のようにPerlのパッケージ名を含んだ関数名を指定することになっています。ダイナミック用には、これを全部小文字にして"::"を"_"に置き換えた名前のPHP関数を利用します。

以下はダイナミックパブリッシング用にsort_methodを定義した例。

plugins/SortableCategories/php/init.SortableCategories.php

Feb 20, 2009

SortableCategories 0.01改め0.02公開

カテゴリやフォルダをユーザの好きなようにソートするプラグイン、SortableCategoriesを作りました。

SortableCategories - ogawa - A plugin for realizing Sortable Categories and Folders. - Google Code

同様の目的のプラグインがいくつかありますが、SortableCategoriesが特徴的なのは以下の点です。

  • Drop & Drop操作でのカテゴリーツリーの編集の実現。script.aculo.usのSortableツリーを利用しています。
  • 最小限のコンストラクトのみでの実現。このプラグインでは、新しいブロックタグやファンクションタグを一切導入しません。言い換えると、できることは限られていますが「これで十分」。

カテゴリツリーを編集するには

  1. まず、「カテゴリの管理」に行きます(「一覧」ドロップダウンメニューから「カテゴリ」を選択します)。
  2. 「カテゴリの管理」の右側に「カテゴリツリーの管理」というリンクが表示されているので、クリックします。
  3. 「カテゴリツリーの管理」画面では、カテゴリツリーを好きなように編集できます。カテゴリまたはサブツリーをつかんで適当な場所に移動させることができます。
  4. 思う存分編集したら「保存」ボタンをクリックすることで現在のツリーの状態を保存することができます。

フォルダツリーも同様にして編集できます。

カテゴリツリーを出力するには

えーと、まずいろいろ誤解があると思うので整理しておきますが、MTのカテゴリ関連のタグ(全37個)は、カテゴリリストに関わるものと、カテゴリツリーに関わるもの、それ以外のものの三種類に分類できます。

SortableCategoriesは順序付きのカテゴリツリーを操作するツールなのですから、関係あるのはカテゴリーツリーに関連するものだけです。このクラスに分類できるタグをざっと挙げると、SubCatIsFirst, SubCatIsLast, HasSubCategories, HasNoSubCategories, HasParentCategory, HasNoParentCategory, IfIsAncestor, IfIsDescendant, SubCategories, TopLevelCategories, ParentCategory, ParentCategories, TopLevelParent, SubCatsRecurse, SubCategoryPathの15個。

このうち、カテゴリツリーのノードの出現順に関係するものとなると、SubCatIsFirst, SubCatIsLast, SubCategories, TopLevelCategories, SubCatsRecurseの5個だけ。

さらに、SubCatIsFirst, SubCatIsLastが使えるのはSubCatsRecurseの中だけですし、TopLevelCategoriesはSubCategoriesにtop="1"という引数を渡しただけのシンタクティックシュガーでしかありません。つまり、SubCategoriesとSubCatsRecurseだけ何とかすればいいわけです(37→15→5→2)。

好都合なことにSubCategoriesにはsort_methodというオプションがあり、カテゴリの階層ごとにカテゴリリストをソートするPerlのメソッドを指定できるようになっています。

つまりは適切なメソッドだけプラグインで提供してやれば用は足りるってことです。それ以外のユーザ定義タグは一切不要だってことです。はぁはぁ。

SortableCategoriesプラグインは、SortableCategories::sorterというsort_method用メソッドを提供しています。これをうまく使うことで「カテゴリツリーの管理」画面で設定した通りにカテゴリーツリーをレンダリングできます。

よく分からないなという人は、「カテゴリアーカイブ」ウィジェットを以下で置き換えれば済みます。

<mt:IfArchiveTypeEnabled archive_type="Category">
<div class="widget-archive widget-archive-category widget">
    <h3 class="widget-header">カテゴリ</h3>
    <div class="widget-content">
    <mt:TopLevelCategories sort_method="SortableCategories::sorter">
        <mt:SubCatIsFirst>
        <ul>
        </mt:SubCatIsFirst>
        <mt:If tag="CategoryCount">
            <li><a href="<$mt:CategoryArchiveLink$>"<mt:If tag="CategoryDescription"> title="<$mt:CategoryDescription remove_html="1" encode_html="1"$>"</mt:If>><$mt:CategoryLabel$> (<$mt:CategoryCount$>)</a>
        <mt:Else>
            <li><$mt:CategoryLabel$>
        </mt:If>
        <$mt:SubCatsRecurse$>
            </li>
        <mt:SubCatIsLast>
        </ul>
        </mt:SubCatIsLast>
    </mt:TopLevelCategories>
    </div>
</div>
</mt:IfArchiveTypeEnabled>

mt:TopLevelCategoriesにsort_method="SortableCategories::sorter"というオプションを与えているだけです。

mt:Categoriesなどで表示されるカテゴリリストはソートされません。それは(小さい文字で長々と説明したように)必要ないからであり、仕様だからです。


まだクオリティ的にアレかもしれませんが、興味がある方は使ってみてください。

Feb 12, 2009

プラグインでMT::Objectのインタフェースを拡張する

リコメンデーションエンジンを実装するためのフレームワークをMTに組み込もうかと思って、少しだけ手を動かしている。

ogawa - Revision 640: /trunk/Recommendable

でもって気がついたのは、ドキュメントされていないけど、プラグインを使ってMT::Objectのインタフェースを拡張できるということだ。

MT::Entryは、デフォルトでMT::Object、MT::Taggable、MT::Scorableを継承している。3つのスーパークラスは論理的には(ディスパッチ順はあるけれども)等価だが、便宜上MT::EntryはMT::Objectのサブクラスで、MT::TaggableとMT::Scorableというインタフェース(Mixin)を使えるように宣言されていると考えると分かりやすい。

ここでは、プラグインを使って、MT::EntryをMT::Taggable、MT::Scorableインタフェースだけでなく、ユーザ定義のLibbleRabbleインタフェースを持つクラスにすることを考える。

まず、plugins/LibbleRabble/config.yaml(プラグイン本体)を用意する。

name: Libble Rabble
id: LibbleRabble
version: 0.01
object_types:
  entry: LibbleRabble

このように書いておくと、entryを定義しているMT::EntryクラスがLibbleRabbleインタフェースを継承するようになる。内部的にはMT::Entryパッケージの@ISA配列の末尾に"LibbleRabble"という文字列が追加されるだけ、これはPerl Mixinの代表的な実現方法の一つ。

LibbleRabbleクラスも用意しておこう。plugins/LibbleRabble/lib/LibbleRabble.pmというファイルを作って中身は適当に書いておけばいい。

package LibbleRabble;
sub libble { print "<\n" }
sub rabble { print ">\n" }
1;

テストコードはこんな感じに書いておけばおk。

#!/usr/bin/perl
use lib 'lib';
use MT::Bootstrap;
use MT;
use MT::Entry;
my $mt = MT->new;
my $e = MT::Entry->load(2);
if ($e->isa('LibbleRabble')) {
  $e->libble();
  $e->rabble();
}

制限事項は、

  • 一つのプラグインで一つのインタフェースしか追加できないよ。
  • ドキュメントされていない仕様(ユーザ定義の新しいデータモデルを追加するための仕組みを流用しているだけ)なのでいつか使えなくなってもしらないよ。
  • リブルラブルに深い意味はないよ。

Feb 7, 2009

最近のアマゾンでのお買い物

最近アマゾンで購入したもの。

創味のつゆは安価で万能。甘いけど甘過ぎないので調節が簡単です。一人暮らしで自炊を始める人にもお勧め。東京でもピーコックなどには置いてありますね。

烏龍茶が切れたので買ってみましたが、はっきり言っちゃうと、これはハズレです。烏龍茶は一旦レベルを上げてしまうと元には戻れないというのを実感しました。冷やして飲むならこれでもいいかもしれませんね。

T-falの鍋は消耗品なので定期的に買い替えています。特に中華鍋は強火で使うので(強火で使っちゃいけないと書いてありますが)買い替えサイクルが短いですね。

すべてアマゾンのアフィリエート収入で購入しました。本当にありがとうございました。

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

Copyright 2012 Ogawa::Buzz | Powered by Blogger
Design by Web2feel | Blogger Template by NewBloggerThemes.com