Saturday, December 5, 2015

Luaのrequireで独自ファイルシステム上のスクリプトをロード

requireでAndroidのAPKのassetsフォルダからスクリプトを読み込みたくて、方法を探ってみました。requireはCのincludeに似た使い方をしますが、requireの実体はモジュール名を引数に取るただの関数です。

dofileとrequireはよく似た関数ですが、いくつか違いがあります。まずrequireは通常拡張子".lua"無しでモジュールを指定します。これを実装してみます。


前回、dofileのファイルシステムを置き換えているので置き換え版のdofileを流用することでLuaだけで書けました。厳密にはpackage.pathを考慮していないという問題がありますが、これだけで用足りることも多いと思います。

ところで、requireで比較的重要なdofileとの違いが、重複requireガードです。これはpackage.loadedテーブルにロード結果が記録される事で行われます。実際にテーブルの中身をprintで出力してみると、以下のようになりました。(左がキー、右が値)
debug   table: 00C9D770
vec4    true
coroutine       table: 00C98AA8
_G      table: 00C92760
package table: 00C98828
math    table: 00C9A2D0
my_class        userdata: 00C9C3B8
io      table: 00C98C38
os      table: 00C99880
bind_win        true
string  table: 00C99FB0
utf8    table: 00C9D6D0
table   table: 00C98BE8
キーを見ると、luaL_openlibsでロードされるLuaの標準ライブラリに混じってrequireでロードしたモジュール(ここではvec4, bind_win, my_classがそれです)の名前が見えます。対して値はそのモジュールをロードした時のreturn値が格納されています。(return値が無い場合はtrue)

また、この値は同じモジュールの二回目以降のrequireで返される値としても使われます。以下の例は、dofileが毎回math.random()を実行するのに対して、requireは初回呼び出し時の値をpackage.loadedにキャッシュする事を確かめるものです。


以上を踏まえたファイルシステム置き換え版のrequireは以下のようになります。

No comments:

Post a Comment