Trac マクロ
Trac マクロとは、 Python で書かれた 'カスタム関数' によって Trac の Wiki エンジンを拡張するプラグインです。 WikiFormatting エンジンが利用可能なあらゆるコンテキストにおいて、マクロを使用することによって、動的な HTML データが挿入されます。
もう 1 種類のマクロは WikiProcessors です。これは通常、 Wiki 以外のマークアップ形式と表示を取り扱うために使用し、多くは、 (ソースコードハイライトのような) より大きいブロックに使用します。
マクロの利用
マクロ呼び出しは、二つの 角括弧 (square brackets) で括られた箇所です。 Python 関数のように、マクロは引数を取ることができ、括弧 (parenthesis) の中に、カンマで区切ったリストで表記します。
Trac マクロは、 TracPlugins としても作成することができます。 TracPlugins として Trac マクロを作成することで「直接 HTTP リクエストにアクセスする。」といった通常の Trac マクロでは実現できない機能を実装することができます。
利用例
'Trac' で始まる Wiki ページの最近の変更履歴 3 件分を表示するマクロです:
[[RecentChanges(Trac,3)]]
は、以下のように表示されます:
2011/12/16
マクロ一覧
Note: 以下に示すリストはマクロドキュメントを含むものだけです。 -OO による最適化や、 mod_python での PythonOptimize オプションが設定されていると表示されません。
[[InterTrac]]
登録済みの InterTrac プレフィックスの一覧を表示します。
[[TitleIndex]]
すべての Wiki ページをアルファベットのリスト形式で出力に挿入します。
引数として、接頭辞となる文字列を許容します: 指定された場合、 生成されるリストにはページ名が接頭辞で始まるものだけが含まれます。 すべてのページがリストされます。
接頭辞の代わりに format や depth を指定することができます:
- format=group: 共通の接頭辞を持つページでリストを生成します。 またmin=nの引数を使用することができ、nにはリストを生成するページの最少数を指定します。
- depth=n: リストするページの階層数を指定します。 0を指定した場合、トップレベルのページのみ表示され、 1を指定した場合、1代目の子ページが表示されます。 何も指定しない場合か、-1を指定した場合、 全てのページが階層構造により表示されます。
[[RecentChanges]]
最近更新されたすべてのページを最後に変更した日付でグループ化し、リストします。
このマクロは、 2 つの引数をとります。最初の引数はプレフィックスの文字列です: プレフィックスが指定された場合、結果のリストにはそのプレフィックスで始まるページのみが 含まれます。この引数が省略された場合は、すべてのページがリストされます。
2番目の引数は結果リストに表示するページの数を制限するために使用します。 例えば 5 に制限すると指定した場合、最近更新されたページのうち、新しいもの 5 件がリストに含まれます。
[[PageOutline]]
現在の Wiki ページの構造的なアウトラインを表示します。 アウトラインのそれぞれの項目は一致する表題へのリンクとなります。
このマクロは 3 つの任意のパラメータをとります:
- 1 番目の引数はアウトラインに含まれる表題の範囲 (レベル) を設定することができ、 数または数の範囲をとります。 例えば、 "1" と指定した場合、アウトラインにはトップレベルの表題のみが表示されます。 "2-3" と指定した場合、アウトラインには、レベル 2 とレベル 3 のすべての表題が ネストしたリストとして表示されます。 デフォルトでは、すべてのレベルの表題が表示されます。
- 2 番目の引数は、タイトルを特定するのに使われます。 (デフォルトはタイトルなし)
- 3 番目の引数はアウトラインのスタイルを指定します。 inline または pullout を指定することができます (後者がデフォルトです) 。 inline スタイルでは、アウトラインをコンテンツの一部として整形しますが、 pullout スタイルでは、アウトラインをフローティングボックスに整形し、 コンテンツの右側に配置します。
[[Image]]
画像を Wiki 形式のテキストに組み込みます。
1 番目の引数は、ファイル名を指定します。ファイルの指定は添付ファイルなど 3つの指定方法があります:
- module:id:file: module に wiki または ticket が指定すると、 その Wiki ページまたはチケットの添付ファイルで file とファイル名が ついているものを参照します。
- id:file: 上記と同様ですが、 id はチケットの短い記述方法か、 Wiki ページ名を指定します。
- file: 'file' というローカルの添付ファイルを指します。これはファイルが 添付されている Wiki ページまたはチケットの中でのみ使用できます。
またファイルはリポジトリのファイルも指定できます。 source:file シンタックスを使用します。 (source:file@rev も可能です)
直接 URL を記述することもできます; /file と記述すると、プロジェクトの ディレクトリからの相対パスになり、 //file と記述すると、サーバルートからの パスになります。また、 http://server/file ではファイルの絶対パスになります。
残りの引数は任意で、 <img> 要素を組み立てる際の属性を設定します:
- 数字と単位は画像のサイズと解釈されます。 (ex. 120, 25%)
- right, left, top, bottom は画像の配置として 解釈されます。
- link=some TracLinks... を指定すると、画像のソースへのリンクが、 TracLinks に置き換えられます。値なしで引数が指定された場合、 リンクは単に削除されます。
- nolink は画像のソースへのリンクを作成しません。 (非推奨, link= を使用してください)
- key=value スタイルは画像の HTML 属性または CSS スタイルの
指示として解釈されます。有効なキーは以下の通りです:
- align, border, width, height, alt, title, longdesc, class, id および usemap
- border は数値での指定のみ可能です。
例:
[[Image(photo.jpg)]] # シンプルな指定方法 [[Image(photo.jpg, 120px)]] # 画像の幅サイズ指定 [[Image(photo.jpg, right)]] # キーワードによる配置指定 [[Image(photo.jpg, nolink)]] # ソースへのリンクなし [[Image(photo.jpg, align=right)]] # 属性による配置指定
他の wiki ページ、チケット、モジュールの画像を使用することができます。
[[Image(OtherPage:foo.bmp)]] # 現在のモジュールが Wiki の場合 [[Image(base/sub:bar.bmp)]] # 下位の Wiki ページから [[Image(#3:baz.bmp)]] # #3というチケットを指している場合 [[Image(ticket:36:boo.jpg)]] [[Image(source:/images/bee.jpg)]] # リポジトリから直接指定する! [[Image(htdocs:foo/bar.png)]] # プロジェクトの htdocs ディレクトリにあるファイル
このマクロは Shun-ichi Goto <gotoh@…> さんが作成した Image.py が 元になっています
[[MacroList]]
インストールされている、すべての Wiki マクロをリストします。 もし利用可能ならばドキュメントも含みます。
非必須オプションとして、特定のマクロの名前を引数として渡すことが出来ます。 この場合、指定されたマクロのドキュメントだけを表示します。
Note: このマクロは mod_python の PythonOptimize オプションが有効になっている 場合は、マクロのドキュメントを表示することが出来ません!
[[TracIni]]
Trac の設定ファイルのドキュメントを生成します。
通常、このマクロは Wiki ページ TracIni の中で使用されます。 省略可能な引数にはコンフィグのセクションのフィルタ、 コンフィグのオプション名のフィルタを指定できます: フィルタで指定された文字列 で始まるコンフィグのセクションとオプション名のみが出力されます。
[[TracGuideToc]]
このマクロは Wiki ページ一式の目次 (ToC) を簡単かつ荒っぽく作成する 例です。
[[TicketQuery]]
指定された条件にマッチするチケットを一覧表示します。
このマクロの引数はカンマ区切りのリストにした、 "key=value" 形式の キー付きパラメータを使用します。
key がフィールド名であった場合、 value は TracQuery#QueryLanguage で 定義されているような、フィルタを指定するシンタックスでなければなりません。 ? の文字で始まる query: リンクで向けの簡素化した URL シンタックス とは 異なります 。
このほか、フィルタとしていくつか名前付きパラメータを使用できます。 これらは検索結果をどのように表示するかを制御できます。すべて非必須です。
format はチケットのリストがどのように表示されるかを決定します:
- list -- デフォルトの表示形式です。チケット ID と概要 (Summary) を 一覧表示します。 1 行ごとに 1 つのチケットを表示します。
- compact -- チケット ID の一覧をカンマ区切りで 表示します。
- count -- 条件に当てはまるチケットの件数のみが表示されます。
- table -- カスタムクエリービューと似た形式で表示されます (ただし コントロールは表示されません)。
max は表示されるチケット数の上限値を指定します (デフォルトは 0 です。これは無制限を意味します)。
order はチケットを整列する列を指定します (デフォルトは id となっています)。
desc はチケットの整列を逆順に行うか指定します。 (デフォルトは false です)。
group はチケットをグループ化を指定します (デフォルトは何も設定されていません)。
groupdesc はグループの表示を逆順とするかを指定します (デフォルトは false となっています)。
verbose を true に設定すると、リストされたチケットの 各行にチケットの説明を表示します。これは table format 専用です。 このパラメータは廃止予定です。代わりに rows を使用してください。
rows パラメータは1行使って表示するフィールドを指定します。 rows=description|summary のように使用します。
Trac 0.10 との互換性のため、マクロは第2引数にキーなし引数が与えられた場合 format として解釈します。 また、フィールドセパレータに使用する "&" は、現時点では動作しますが、この機能は廃止予定です。
[[InterWiki]]
登録済みの InterWiki プレフィックスの一覧を表示します。
[[TracAdminHelp]]
trac-admin コマンドのヘルプを表示します。
例:
[[TracAdminHelp]] # 全てのコマンド [[TracAdminHelp(wiki)]] # 全ての wiki コマンド [[TracAdminHelp(wiki export)]] # "wiki export" コマンド [[TracAdminHelp(upgrade)]] # upgrade コマンド
世界のマクロを共有
Trac Hacks というサイトは、コミュニティに寄稿されたマクロと プラグイン を収集し提供しています。新しいマクロを探している、共有したいマクロを作成した、などの場合は遠慮なく Trac Hacks のサイトを訪問してください。
カスタムマクロを開発する
マクロは、 Trac 自身と同じように Python で書かれています。
マクロの開発についての詳しい情報は リソースの開発 を参照してください。
マクロの実装
Trac 0.11 でマクロを作成する簡単な例を 2 つ紹介します。
古いマクロと新しいマクロの違いを示す例は Timestamp.py を参照してください。また、古いマクロから新しいマクロに移行するための情報は macros/README を参照してください。
引数なしのマクロ
Trac は マクロ名としてモジュール名を使用するので以下は TimeStamp.py という名前で保存しなければなりません。
from datetime import datetime # Note: since Trac 0.11, datetime objects are used internally from genshi.builder import tag from trac.util.datefmt import format_datetime, utc from trac.wiki.macros import WikiMacroBase class TimeStampMacro(WikiMacroBase): """Inserts the current time (in seconds) into the wiki page.""" revision = "$Rev$" url = "$URL$" def expand_macro(self, formatter, name, args): t = datetime.now(utc) return tag.b(format_datetime(t, '%c'))
引数付きのマクロ
Trac は マクロ名としてモジュール名を使用するので以下は HelloWorld.py という名前で (plugins/ ディレクトリ内に ) 保存しなければなりません。
from trac.wiki.macros import WikiMacroBase class HelloWorldMacro(WikiMacroBase): """Simple HelloWorld macro. Note that the name of the class is meaningful: - it must end with "Macro" - what comes before "Macro" ends up being the macro name The documentation of the class (i.e. what you're reading) will become the documentation of the macro, as shown by the !MacroList macro (usually used in the WikiMacros page). """ revision = "$Rev$" url = "$URL$" def expand_macro(self, formatter, name, args): """Return some output that will be displayed in the Wiki content. `name` is the actual name of the macro (no surprise, here it'll be `'HelloWorld'`), `args` is the text enclosed in parenthesis at the call of the macro. Note that if there are ''no'' parenthesis (like in, e.g. [[HelloWorld]]), then `args` is `None`. """ return 'Hello World, args = ' + unicode(args) # Note that there's no need to HTML escape the returned data, # as the template engine (Genshi) will do it for us.
訳注 重要:
Wiki マクロが引数を持つ場合、引数は必ずサニタイズしてください。 expand_macro の戻り値は <script> タグやイベントハンドラなどもそのまま出力するので、入力をチェックせずに、そのまま戻り値に使用するのは極めて危険です。 Genshi の tag オブジェクトにラップすれば、エスケープ機構が働きますので、通常はこれを使うとよいでしょう。 HelloWorld.py は、以下の通り書き直すことができます:
from trac.wiki.macros import WikiMacroBase from genshi.builder import tag class HelloWorldMacro(WikiMacroBase): def expand_macro(self, formatter, name, args): return tag.div(u'Hello World, args = ', unicode(args))
expand_macro について
expand_macro は HTML として解釈できる単純な文字列か Markup オブジェクト (from trac.util.html import Markup を使用する ) のどちらかを返さなければなりません。 Markup(string) はそのまま string を解釈するので、 HTML 文字列はエスケープされずに、そのとおり表示されます。 Wiki フォーマッタを使用した場合は from trac.wiki import Formatter のように import してください。
マクロで HTML ではなく Wiki マークアップを使用したい場合、以下のように HTML に変換します:
text = "whatever wiki markup you want, even containing other macros" # Convert Wiki markup to HTML, new style out = StringIO() Formatter(self.env, formatter.context).format(text, out) return Markup(out.getvalue())