XPCOM取得用ずぼら関数

欲しいXPCOMを得るのに長々と書くのがつらくなってきたので手抜きをする関数xpc()を作ってみた。
通常時

Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream);

xpc()使用時

xpc('create','network/file-output-stream;1');

使い方

xpc(動作モード,コンポーネントクラス名,[コンポーネントインターフェイス名])

引数はすべて文字列。
動作モードは、'createInstance'または'getService'を指定する。
(が、実際には最初の1文字が'c'かどうかしか見てないので、途中まででもいい。)
コンポーネントクラス名は、'@mozilla.org/'の部分を省いて指定する。
(逆に言えば、'@mozilla.org/'で始まるものにしかこの関数は使えない。)
コンポーネントインターフェイス名を指定した場合はそれがそのまま使われる。
コンポーネントインターフェイス名を省略すると、コンポーネントクラス名からでっち上げる。
具体的には、コンポーネントクラス名での、スラッシュから前(例:「network/」)とセミコロンから後(例:「;1」)を取り除き、
先頭の文字とハイフンで繋がれた直後の文字を大文字にして、先頭に'nsI'をつけたものを使う。

裏仕様

コンポーネントインターフェイス名では一部が大文字になっているが、コンポーネントクラス名ではハイフンが使われていない場合がある。
こういう場合は、コンポーネントクラス名自体に大文字を使って指定する。
コンポーネントクラス名部分は実際には小文字化されるので大丈夫。

xpc('get','intl/ScriptableUnicodeConverter');

これは以下のように展開される。

Components.classes['@mozilla.org/intl/scriptableunicodeconverter'].getService(Components.interfaces.nsIScriptableUnicodeConverter);

(この辺の命名規則が統一されていれば本当はこんなバッドノウハウは必要ないんだろうけど…)

関数本体

function xpc(m,c,i){
  return Components.classes['@mozilla.org/'+c.toLowerCase()]
    [m.match(/^c/) ? 'createInstance' : 'getService']
    (Components.interfaces[i||'nsI'+c.replace(/.*\/|;.*/g,'')
     .replace(/(^|-)(.)/g,function(a,b,c){return c.toUpperCase();})]);
}