2013年3月から追加されたMediaWikiの拡張機能「Scribunto」の実装により、ウィキペディア日本語版ではプログラミング言語Luaを利用したスクリプトを作成することが可能になりました。主にテンプレートの機能を向上させる目的で使用され、Luaのソースコードテンプレートに組み込んで、{{#invoke:}}という構文を使って呼び出すことができます。Scribunto拡張は2022年3月時点でLua 5.1.5をサポートしています。

Luaのソースコードは、モジュール空間(例:モジュール:Bananas)に置かれます。そして、各モジュールを、テンプレートとして別なページから呼び出せるようになっています(例えば、モジュール:Bananas/docでは、{{#invoke:Bananas|hello}}と書くことで、「Hello, world!」という出力を得ています)。

モジュールを実行する 編集

ウィキペディアの一般的なウィキページでモジュールを実行するには#invokeというパーサー関数(→Help:マジックワード)を使用します。#invokeの書き方はテンプレートのそれと似ているが、若干違うところがあります。すなわち、#invokeでは「関数名」を指定する必要があります。関数とは入力を取得して処理を行い、出力を返す一連の命令であり[注 1]、テンプレートと似ていますが、1つのページには1つのテンプレートしか定義できないのに対し、1つのLuaモジュールには複数の関数を定義できます。

また、Luaモジュールを直接実行することはできず、必ずモジュールの関数を1つ選んで実行しなければなりません。モジュールは関数のコンテナにすぎず、それ自体は何もしません。そのため、関数名を指定する必要があります。

ウィキページでモジュールを実行するには{{#invoke:モジュール名|関数名}}のように書きます。

例えば、モジュール:Bananasの"hello"関数を実行するためには下記のように書きます。

  • {{#invoke:Bananas|hello}} → Hello, world!

引数を渡す 編集

モジュールに引数を渡すときの書き方はテンプレートに引数を渡す書き方と同じです。しかし、1つ目のパイプ"|"の後ろに書くのは関数名なので、1つ目の名無し引数は2つ目のパイプの後ろに書かれます: {{#invoke:モジュール名|関数名|1つ目の名無し引数|2つ目の名無し引数|引数名=引数の値}}

例えば、モジュール:BananasArgsの"hello"関数では1つ目の名無し引数の指定によって出力が違います。

  • {{#invoke:BananasArgs|hello|Kate}} → Hello, Kate!
  • {{#invoke:BananasArgs|hello|Fred}} → Hello, Fred!

BananaArgsの"count_fruit"関数ではbananasapples引数を受け入れます。

  • {{#invoke:BananasArgs|count_fruit|apples=3|bananas=4}} → I have 4 bananas and 3 apples
  • {{#invoke:BananasArgs|count_fruit|bananas=5|apples=2}} → I have 5 bananas and 2 apples

多くのモジュールには解説サブページがあり、使える引数とその効果を説明します。

サンプルモジュール 編集

Luaスクリプトの作成依頼 編集

ウィキペディア日本語版で特定のタスクを行うためにLuaスクリプトが必要になった場合、プロジェクト:ウィキ技術部にて依頼を提出することができます。

導入までの経緯 編集

Luaは長年にわたる議論を経て、2012年にテスト用としてtest2.wikipedia.orgに導入され、すべての編集者に試験運用を勧める知らせが出されました(2012年8月のお知らせを参照)。その後、Luaはウィキメディアのテストウィキとmediawiki.orgでの試験運用を経て、2013年2月にウィキペディア英語版に導入され、3月にはウィキペディア日本語版に導入されました(2013年3月のお知らせを参照)。

Luaについて 編集

Luaはデータの解析、式の演算、文字の書式化などを、オブジェクト指向として行えるスクリプト言語です。言語自体は理解しやすいようシンプルになっていますが、表、動的関数、添字に文字列を使える連想配列など、複雑な構造も使えるようになっています。再帰のような複雑な構造もとれますが、いたずらに複雑なモジュールを作って、第三者が誰も理解できない、ということがないように注意してください。

以下に、モジュール:HelloWorldにあります、Hello, World!プログラムのソースコードを示します。

-- WikipediaのLuaモジュールは、外部からアクセスできる関数を入れる変数の
-- 宣言から始める必要があります。この変数の名前は何でもよく、変数にデータを入れることもできます。
local p = {};

-- そして、変数に関数を追加します。そうすることで、Wikipediaから#invokeして呼び出せるようになります。
-- frame変数には、呼び出し時にWikipediaから渡されるデータが入ります。
p.hello = function( frame )

    -- ローカル変数を宣言して"Hello World!"に初期化
    local str = "Hello World!"

    -- str変数の中身をWikipedia側に戻して関数を脱出します。
    -- printのような関数は使えないので、出力はこのように文字列の返り値でやり取りします。
    return str

-- hello関数の終わり
end

-- モジュールの終わりでは、関数を含んだ変数をWikipedia側に返します。
return p

-- こうすれば、{{#invoke: HelloWorld | hello }}のような形でこのモジュールを使えます。
-- #invokeでは、直後にモジュール自体の名前、次の引数に関数名を渡します。

MediaWikiでLuaを使う上でのガイドが、mw:Extension:Scribunto/Lua reference manual/jaにあります(翻訳途中)。

ユニットテスト 編集

ウィキペディアにおけるLuaスクリプトのユニットテストを行うためのフレームワークはモジュール:UnitTestsにあります。このフレームワークでは特定の入力でスクリプトを実行し、出力が予想値と同じであるかを確認できます。ユニットテストはスクリプトの変更により生じる問題を早期に発見できます。

慣例では特定のモジュール(例: モジュール:Bananas)のユニットテストはtestcasesサブページ(例: モジュール:Bananas/testcases)に置かれ、モジュール‐ノート:Bananas/testcases{{#invoke: Bananas/testcases | run_tests}}のように実行します。テスト用メソッドの名前は必ず"test"で始まります。下記にModule:Bananas/testcasesより簡単な例を1つ記します。

-- [[Module:Bananas]]のユニットテスト例です。ノートをクリックして動作確認をしてください。
local p = require('Module:UnitTests')

function p:test_hello()
    self:preprocess_equals('{{#invoke:Bananas | hello}}', 'Hello, world!')
end

return p

ユニットテストが作成されたモジュールの一覧は特別:リンク元/モジュール:UnitTestsをご参照ください。

Wikipedia固有のポイント 編集

概要 編集

Luaの入力としては、{{#invoke:}}で渡されたテキストの引数と、frameにある関数群だけがウィキペディアから情報を得るために使えます。そして、Luaからの出力では、テンプレートなど{{...}}で書くようなものを含むことはできません。さらに、Luaの実行時間は10秒以内という制限もあります(ページのソースを見れば、処理時間を確認できます)。また、通常のLuaから削ってある関数もいろいろとあります(mw:Extension:Scribunto/Lua reference manual#Differences from standard Luaに詳細があります)。

Luaへの入力 編集

ScribuntoにおけるLuaの実行は、ページのパース時に行われるので、ページに書き込んだ情報以外を使うこと、たとえば入力ボックスを作って入力させるとか、マウスの位置を検出するとかといったことは不可能です。Luaの入力としては、他のページをトランスクルードすることはできますが、SVGファイルを含めメディアファイルやカテゴリの中身、特別ページの内容は取得できません。

ウィキテキスト 編集

いわゆるパイプの裏技[[Wikipedia:ヘルプ|]])は、Luaの出力中では適用されないので、[[Wikipedia:ヘルプ|ヘルプ]]のように省略しない形で書く必要があります。また、~~~~が署名へ展開されることもありません。別なテンプレートの呼び出し、マジックワード、条件文など{{...}}で書くものや、<ref><nowiki>といった、MediaWiki側で処理するタグも、Luaの出力中では処理されません。

モジュールのインポート 編集

モジュール名前空間にある別のLuaスクリプトを使いたい場合はrequire()を使います。

extern_hello=require("モジュール:HelloWorld")としてモジュールを読み込んだ上で、extern_hello.hello()のように呼び出します。

Luaを使用するテンプレート 編集

Luaを使用するテンプレートの解説サブページには{{Lua}}テンプレートを追加してください。Luaが使用されていることを明示できます。

注釈 編集

  1. ^ ウィキページで実行する関数では出力を1つだけ返すことが大半です。出力を2つ以上返す関数は一般的にはウィキページで実行することを想定しておらず、ほかのモジュールや引数で実行することを想定しています。

関連項目 編集

ウィキペディア内のページ 編集

MediaWikiにおける解説ページ 編集