プラグイン

BlosxomのプラグインアーキテクチャによってBlosxomの核となる部分は軽量かつスマートのままに、異なる環境や利用方法に対する拡張性を提供しています。

プラグイン

プラグイン登録ページ...

プラグインの登録ページを見て必要なプラグインを探して下さい。

そこにはちょうど貴方のようなBlosxomユーザが開発したプラグインがリストアップさえており、成長を続けています。そこではプラグインが陳列されていて、プラグインについてのコメントを読んだりしたり、他にも追加テンプレートがあったりします。画像プラグインは画像参照からサイズ変更まで全てを提供していますのでギャラリーを構築する事ができます。入力系のプラグインは返信(コメントとトラックバック)、因果関係の追跡、メールをウェブログにすると言った機能を提供しています。

コミュニティと共有できるプラグインをお持ちですか? ここでプラグを差してください!

プラグインとは?

Perlをある程度知っていればBlosxomのプラグインを書く事ができます。プラグインは単純なPerlスクリプトで、Blosxomがアクセスすることのできるpluginsディレクトリに置き、Blosxomの実行時に特定の位置で呼び出されるサブルーチンや関数を定義します。

プラグインを使う...

ユーザ向けのプラグインドキュメントでプラグインサポートの有効化、プラグインのインストール、プラグインの実行順番の変更、プラグインの削除等を理解して下さい。

Pluginの心...

もちろん、貴方の好きなようにすればよいのですが、私はBlosxomのプラグインは誰もがその力のコンビネーションと簡単使用を十分に感じ取れ、そしてBlosxomの魂を感じて欲しいと望むのです。どうぞできるだけ簡単にインストールでき、設定でき、そして動作できるよう、心がけて下さい。

理想的には、プラグインとはpluginsディレクトリにドロップできる単一ファイルであり、オプションで環境を設定できるものです。

何か追加する必要があったり、他のモジュールを必要とする場合にはプラグインとしてそれら全てを提供し、pluginsフォルダに一まとめにしてドロップできるようにサブディレクトリにまとめるようにして下さい。ユーザが専門家になったりコンパイルしたりPerlモジュールをインストールしなくてはならないなど、過度な条件を必要としないようにして下さい。

また、常にクロスプラットフォームの問題を念頭においてください。Blosxomはどこでも動作する。私が作成した全てのモジュールがそうであるように。私は何か少しセクシーさに欠けるものがどこでも快調に動作する一方でLinuxでのみ動作する何かセクシーなものを作成するのは恥ずかしく思っています。

プラグインを書く...

Blosxomのプラグインアークテクチャを理解する最も良い方法は、順番に各項目を進んでいくことです。

...Blosxom変数

各プラグインで可能なことは、キーとなるBlosxomの変数(読み込み:通例では読み込み専用)を参照する事です。その大部分はBlosxom#--- Configurable varibles ---セクションに現われ、設定ドキュメント内で説明されています。以下は完全な変数リストです:

  • $blog_title
  • $blog_description
  • $blog_language
  • $datadir
  • $url
  • $depth
  • $num_entries
  • $file_extension
  • $default_flavour
  • $plugin_dir
  • @plugins
  • $static_dir
  • $static_password
  • @static_flavours
  • $static_entries
  • $path_info
  • $flavour
  • $static_or_dynamic
  • $output
  • $version

これらの変数の全てはメインのBlosxomの名前空間で使えます。$blosxom::datadir@blosxom::pluginのようにして参照します。

各サブルーチンに適切に渡された変数は参照と変更のためにコンテキストに固有なものです(例 話題の本文の参照はstory()サブルーチンに渡されます)。

...良いスタートを切る

全てのプラグインはプラグインの識別で始まる事になっています。幾つかのコメントが付いた慣例の行で始まるのが良い方法です...

# Blosxom Plugin: sample
# Author(s): Rael Dornfest  
# Version: 0+1i
# Blosxom Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/

貴方のプラグインはそのプラグインの名前空間で操作するようにして、他のプラグインと全ての変数とサブルーチンが競合しないようにすべきです。Perlではpackageでこれを行います:

package sample;

この例では、sampleと言う名前のパッケージになります。

各プラグインはそれ自身のパッケージで動作するだけでなく、それ自身のファイルに置きます。ファイルはpluginsディレクトリに置くようにし、ファイル名はパッケージ名と厳密に同じ名前にしなくてはなりません。そのため、この例ではプラグインはplugins/sampleとなります。

プラグインが読み込まれる順番をコントロールしたいのであれば、ファイル名を次のようにします:00loadfirst50loadsomtime99loadlast等。プラグインはアルファベット順で読み込まれるのでこのようにすると順番を強制的に変更する事ができます。Blosxomはプラグイン名から数字を取り外すのでパッケージ名でプラグインを参照できます(例 loadfirst)。

...環境設定、変数、モジュール

ここからは貴方のPerlは自由に動作します。以下は理解、使用、貴方へのプラグインへの適用についての私の提案です。

Blosxomそれ自体ではユーザが変更できる変数は一緒にまとめるべきです。ファイルの先頭から環境設定変数部分の全てはユーザへの情報と変更を意図したものにすることを提案します。以下のような感じです:

# --- Configration Variables -----
$email_address = 'me@example';
# --------------------------------

環境設定変数はユーザがプラグインを適切に使えるようにするために必要なものにすべきです。

プラグインに便利な変数を定義する時間です:

$title_and_path = '';
$story_number = 1;

貴方が定義したこれらの変数の全てはフレーバーテンプレートで使用できます。それには名前空間を付加して$title_and_pathはテンプレート内で典型的なPerlスタイルの$sample::title_and_pathで参照されます。

実際のところ、プラグインアーキテクチャの使用はBlosxom本体に無い変数を貴方が単に定義することです。

貴方のプラグインに必要なPerlモジュールを必要とするには以下のようにします。もしかするとCGIモジュールの素晴らしい関数にアクセスする必要があるかもしれません:

use CGI qw/:standard/; 

...サブルーチン

Blosxomのプラグインアーキテクチャは一連のフックを定義します。これは各プラグインが動作する機会を与えるBlosxomの実行内の場所です。これらのフックは --単にサブルーチンです-- は実行の順番があります:start, entries, filter, head, sort, date, story, foot, end。唯一必要なサブルーチンはstartです。

...サブルーチン ...start

startサブルーチンが必要です。これの目的は読み込むプラグインがあり、そしてそれらを有効にするようにするという事をBlosxomに知らせることです。 Blosxomの流儀ではそれを1(true)を返すことで行います。以下は最も簡単な例です:

sub start {
   1;
}

これはBlosxomにプラグインが生きていて各コールバック地点でプラグインが振舞えるようにと言う事をBlosxomに知らせます。

startルーチンは動的、または静的表示にプラグインの操作を制限する完全な位置です:

sub start {
   return $blosxom::static_or_dynamic eq 'dynamic' ? 1 : 0;
}

上記例ではBlosxomが現在動的に動作している場合にのみプラグインが動作するようにしています。そうでない場合にはプラグインの動作を停止させます。

...サブルーチン ...template

templateサブルーチンはプラグインに標準のtemplateサブルーチンを置き換える機会を与えます(一つは貴方のテンプレートを提供するものです)。

templateフックは標準(Blosxom本体で$templateで定義され割り当てられている)の場所で使われる匿名関数への参照を返さなくてはなりません。

パス、テンプレート、チャンク(例 "head""foot")そしてフレーバーを与えます。サブルーチンはテンプレートコンポーネントのコンテンツを返さなくてはなりません。

以下の例ではメインのデータディレクトリではなくて代わりの"flavour"ディレクトリからテンプレートを読み込みます。ウェブログ記事からはフレーバーを切り離しています:

sub template {
   return sub {
     my ($path, $chunk, $flavour) = @_;
     
     $path =~ s!^/*!!; $path = "/$path";
     my $p = $path;
     do {
       return join '', <$fh> if 
       $fh->open("< $flavour_dir/$p/$chunk.$flavour");
     } while ($p =~ s/(\/*[^\/]*)$// and $1);
     return join '', ($blosxom::template{$flavour}{$chunk} 
                      || $blosxom::template{error}{$chunk} 
                      || '');
   };
 }

貴方のプラグインがデフォルトのものを上書きしないようにする場合は単に未定義の値を返しすようにします:

sub template {
  # 
  return undef;
}

このようにすると後続のプラグインは標準のtemplateサブルーチンを上書きする機会を与えられます。

...サブルーチン ...entries

entriesサブルーチンはデフォルトの記事検索サブルーチン(貴方の全てのウェブログ記事を見つける)を置き換える機会を提供します。

entriesフックはBlosxom本体で$entriesとして定義されてる標準のものを扱う匿名関数への参照を返さなくてはなりません。

サブルーチンはファイルのハッシュと他のインデックス(静的表示の場合)への参照を返さなくてはなりません。

以下の簡単な例は%filesハッシュを一つのログ、 $datadir/just/one/story.txtに関連付けします:

sub entries {
  # 
  return sub {
     my(%files, %indexes);
    # 
    $files{"$blosxom::datadir/just/one/story.txt"} = 
       stat("$blosxom::datadir/just/one/story.txt")->mtime;
    # 
    # indexes to be constructed when building statically
     return (\%files, \%indexes);
   };
}

より総合的で現実的な例がentries_indexプラグインで見られます。

標準のものを上書きしたくない場合には単に未定義の値を返すようにします:

sub entries {
  # 
    return undef;
}

後続のプラグインは標準のentriesサブルーチンを上書きできる機会を与えられます。

...サブルーチン ...filter

filterサブルーチンはデータディレクトリBlosxomが見つけた全ての記事のリストを変更する機会を与えます。

サブルーチンにはファイルのハッシュへのリファレンス($files_ref)を渡します。ハッシュは キー/値 からなり、キーは記事のフルパスで、値はUnix形式の修正時間(mtime)です。

sub filter {
   my($pkg, $files_ref) = @_;
   1;
}

フィルタリングの一つの例として、ローカル検索の結果に基づいてリストを再構築するものを紹介します。これを行うLuceneプラグインを私のサイトで使っています。以下の例は"spiffy"と言う単語を含まない全てのファイルを取り除きます:

sub filter {
   my($pkg, $files_ref) = @_;

   foreach ( keys %$files_ref ) {
     $_ =~ /spiffy/ or delete $files_ref->{$_};
   }
   1;
}

1でサブルーチンが終了していることに注意して下さい。意図したように動作した場合にtrue(1)を返すのが正しい流儀です。問題が生じた時にはfalse(0)を返すようにします。Blosxomは0の実行や何か実行が厳しい時に中断しません。静的に動作している時に各プラグインで何が起こったかをレポートします。

...サブルーチン ...skip

skipサブルーチンはBlosxomが実際に出力を生成するのを開始する時に呼び出されます。プラグインは1を返すことでログを短く切り出す事ができます。もちろん1を返す最初のプラグインは呼び出された最後のプラグインです。

skipルーチンは便利で、例えば、プラグインが何らかの理由によりリダイレクトを返したり、ブラウザにバイナリストリームを送信したり(例 画像)、わざわざウェブログの記事を生成する理由が無い場合などです。

...サブルーチン ...interpolate

interpolateサブルーチンはデフォルトの置換サブルーチンを置き換える機会を提供します($title$someplugin::somevarialeを置き換えます)。

interpolateをフックする最初のプラグインはblosxom.cgi自体の中の$interpolateに関連したコードを持つデフォルトの場所で使われる匿名関数へのリファレンスを返します。

$interpolateに割り当てられたサブルーチンはテンプレートコンポーネントを呼び出します(例 headstoryfoot)。適切な置換のためにコンテンツを渡します。

interpolate_conditionalプラグインは、例えば、次のものを含む条件付置換の全ての約束を提供します。定義された、定義されていない、*に一致、*より大きい、*より小さい、再帰(話題自体無いにテンプレート変数を使うことで可能です)。

プラグインが何も上書きをしたくない場合には単に未定義の値を返しすようにします:

sub interpolate {
   # for some reason determine that you don't want to override the default...
   return undef;
}

後続のプラグインは標準の置換サブルーチンを上書きする機会を得ます。

...サブルーチン ...head

Bloxsomhead.flavourで読み込んだ後、そしてテンプレートコンポーネントに対して値の入れ替えを行う前にheadサブルーチンを呼び出します。

このサブルーチンには現在の作業ディレクトリ(パスで定義されている)と生のhead.flavourソースへの参照を渡します。

sub head {
   my($pkg, $currentdir, $head_ref) = @_;
   1;
}

headサブルーチンは出力ストリームをヘッダに追加する前に生のヘッダソースを変更し、または何らかの変数を変更する機会を提供します。

これはまた、これらのカスタムな話題に関係の無いテンプレート変数を変更するのに良い手段です。ここでは、例えば、タイトルへのURL行に渡したパスを追加しています。"::"ではさまれています。

sub head {
   my($pkg, $currentdir, $head_ref) = @_;
   $title_and_path = $blosxom::blog_title;
   $blosxom::path_info and $title_and_path .= " :: /$blosxom::path_info";
   1;
}

私は私のhead.flavour$blog_title::$path_infoを単純に含める事でこれを達成していません。なぜならURL行にパスが特定されていない場合に"::"が表示されてしまうので、"raelity bytes::"を作成しています。

より試験的ではない例は私のサイトで使用しているreadmeプラグインを作成するために使っています。現在の作業ディレクトリ($currentdir)に現われたreadme、またはreadme.flavourファイルが読み込まれ、生のヘッダソースに追加されます($head_ref)。

...サブルーチン ...sort

sortサブルーチンは表示するウェブログの順番(標準では日付順:新しいのが最初)を決定する標準の並べ替えサブルーチンを置き換える機会を提供します。

entriesフックはblosxom.cgi本体で$entriesに割り当てられてた標準の場所で使われてい匿名関数への参照を返さなくてはなりません。

このサブルーチンは完全限定のファイル名のリストを返さなくてはなりません。

以下の例は日付順(古いのが先)で記事を並べ替えます。これは標準とは逆です:

sub sort {
   return sub {
     my($files_ref) = @_;
     return sort { $files_ref->{$a} <=> $files_ref->{$b} } keys 
     %$files_ref;
   };
}

何も上書きしたくない場合には単に1を返しすようにします:

sub sort {
  #
  return undef;
}

後続のプラグインは標準の並べ替えサブルーチンを上書きする機会を得ます。

..サブルーチン ...date

Bloxsomは日付が新しくなるとdateを呼び出します。それは適切なdate.flavourで表示した後で、そしてテンプレートコンポーネントのための値を入れ替える前です。

このサブルーチンには現在のディレクトリと生のdate.flavourソース、Unixスタイルの日付に対する最新の記事の修正日、そして修正日から来る幾つかの便利な日付が渡されます。

sub date { 
  my ($pkg, $currentdir, $date_ref, $mtime, @date_bits) = @_;
  my($dw,$mo,$mo_num,$da,$ti,$yr) = @date_bits;
  1; 
}

dateは生のdateテンプレートの修正と完全に新しい日付の構築の機会を提供しています。以下のコードは、例えば、英語の月の名前をフランス語、日本語等に変換します。

sub date {
   my ($pkg, $date_ref, $mtime, $dw,$mo,$mo_num,$da,$ti,$yr) = @_;
   # 
   $$date_ref =~ s/\$mo(?!_num)/$months[$mo_num]/mg;
   1;
}

...サブルーチン ...story

Bloxsomstoryを各々、そして全ての記事に対して呼び出します。それは適切なstory.fvalourで読み込んだ後と、テンプレートコンポーネントに対して値を入れ替える前です。

このサブルーチンには記事のパス、ファイル名、生のstory.flavourソースへの参照、記事のタイトルへの参照、そして記事の本文への参照が渡されます。

sub story {
   my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref)
   1;
}

生のstory.flavourソースの変更、テンプレートに渡される前にタイトルと本文の変更等が行えます。

簡単な例として、ウェブログの番号を表す$story_number変数を使ってみましょう。

sub story {
   my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref)
   $$title_ref = "#" . $story_number++ . ". " . $$title_ref;
   1;
}

または、より良い例として私のサイトで使っている単純化した(十分では有りませんが)TrackBackプラグインをあげてみましょう。これはスタンドアロンのTrackBackからトラックバックの数を取り出し、$trackback変数に結果を保存します。値は私のstory.flavour内で$trackbacks::trackbackと入れ替えられます。

$trackback = '';

sub story {
   my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref)
   
   #

   $trackback = 
     qq{<a href="$tb_url?__mode=list&tb_id=$tb_id">trackbacks ($tb_count)</a>};
   1;
}

..サブルーチン ...foot

headサブルーチンと似て(レコードのA面とB面のような関係)、Blosxomは適切なfoot.flavourで読み込んだ後、そしてテンプレートコンポーネントに対する値の入れ替えの前にfootサブルーチンを呼び出します。

このサブルーチンには現在の作業ディレクトリ(パスで定義される)と生のfoot.flavourソースへの参照が渡されます。

sub foot {
   my($pkg, $currentdir, $foot_ref) = @_;
   1;
}

footサブルーチンは生のフッタソースの変更や出力ストリームへのフッタの追加の前の変数の変更を提供します。

...サブルーチン ...end

endサブルーチンは最後に呼び出されます。それは全ての出力が処理されてブラウザに送られた後で、Blosxomが実行を終了する前です。

sub end {
   1;
}

このサブルーチンには何も渡されません。

ここはクリーンナップまたは便利と思う処理を行う最後の場所です。私はたくさんの利用方法を見つけました。それは"touch file"の修正日から何か変更がある場合かどうかweblogs.compingを打ったり何時間も経過したあとに新しいウェブログを投稿したと言う事をメーリングリストにメールを送信するような使い方です。

...サブルーチン ...last

lastサブルーチンフックはブラウザで表示される、またはファイルを保存する(静的表示の場合)と言うよりも、ヘッダが出力され、全てのkit-and-karboodleが生成ルーチンで返される前に呼び出されます。

このサブルーチンにはBlosxomから何も渡されません。