gotin blog

Whatever gotin wanna write

g_editor.user.js の仮想ファイルシステムについて

仮想ファイルシステムなんてたいそうな名前をつけてしまいましたが、
全然たいしたことないしょぼいものですので、その説明(言い訳)を書いておきます。

Greasemonkeyにはスクリプトごとに永続データを管理するためのしかけがあって、
そのためのAPIとして
GM_setValue(<名前>,<記録データ>)

GM_getValue(<名前>)
があります。

名前をつけてデータを管理できるわけですが、
管理対象のデータはstringのみです。確か。

なので、オブジェクトや配列をそのまま記録することはできません。
ではどうするか?オブジェクトや配列をJSON文字列に変換して記録するようにすればいいわけです。
記録したデータを元に戻すときは記録してあるJSON文字列をevalしてあげます。

ということでGreasemonkeyでもJSON文字列変換処理をかますことによって
(多分)任意のデータを永続化しておくことができます。

さて問題の仮想ファイルシステムですが、
ホントにたいしたことはしていなくて、
ファイルやディレクトリとして何があるのか、というデータ(以下エントリデータ)と、
個々のファイルの中身のデータをGM_set/getValueで記録しています。

エントリデータはオブジェクトとして記録していて、
ディレクトリならオブジェクト、
ファイルなら"file"という文字列として記録しています。
ディレクトリはどういうオブジェクトになっているかというと、
その中で持っているファイルやディレクトリを、それらの名前を属性として持つ
オブジェクトになっています。
例えば、


/

-user/
-gotin/
-test.txt
-init.js
-test.js


なんていう状態の場合、

{"user":{"gotin":{"test.txt":"file"}},
"init.js":"file",
"test.js":"file"}

という具合です。


ファイルの方はファイルパスを名前として中身を記録しています。
記録するときは


GM_setValue("/init.js",");

ロードするときは

GM_getValue("/init.js");

という具合です。

ね。たいしたことないでしょー。ごめんなさい><

で、悩んだのがファイルやディレクトリの削除はどうするのか、ということなんですよね。
GM_clearValueなんてないんですよ、困ったことに。
それとJavaScriptのオブジェクトから属性の存在そのものを消す方法がない(のかどうかも分からない)んです
→オブジェクトから属性の存在を削除するには delete(演算子?) を使えばよいのでした。

仕方ないので削除するときは
例えば/test.jsを消したいのであれば、


GM_setValue("/test.js", null);

として、エントリデータのほうは、

{"user":{"gotin":{"test.txt":"file"}},
"init.js":"file",
"test.js":null}


delete <ルートディレクトリ>["test.js"] ;

としておいて、JSON文字列化処理のときに値がnullであるような要素は出力しないようにして、
(↓こうなる)

{"user":{"gotin":{"test.txt":"file"}},
"init.js":"file"}

GM_setValueし、それをevalしたものをエントリデータとして持つようにする、ということにしました。


ということでファイルシステムなんて大げさすぎるので、
なんかいい名前ないもんでしょうかね。

ツリー形式のファイル管理、でいいか。^^;



[追記]
Greasemonkeyではなぜだか日本語文字列をうまいこと扱ってくれないので、
ファイルの中身を記録・再現するときはencodeURIComponent/decodeURIComponentをかましています。
念のため。

"file"なんてやってないで、そこにそのままファイルの内容を入れればいい気がしてきた。
そうすれば、削除済みファイルの断片が残らずに済む。
でもそうすると深い階層のファイルを開くときにちょっと効率が悪いかなーと思って
今の実装にしたんだけど、まぁいいか。

[さらに追記]
最新版のgmacs.user.jsではファイルの中身もツリーの要素に突っ込むことにして、GM_setValueされたものでいっぱいにならないようにしました。
今までの実装だとファイルを作ってから削除してもGM_setValueのエントリそのものは消えなかったわけですが、新しい実装だとファイルをいくら作ってもgmacs.user.js(g_editor.user.jsの新名称)自体のGM_setValueのエントリはツリー要素一つだけなのでエントリで散らかることを防いでいます。
詳しいことはソースを読んでいただけるのが一番かと^^;
といっても読みやすく工夫したりはしてませんが。。。