« 勝手に続:DBIx::Tracerを使って流れているSQLのテストをしてみた話 | メイン | Test::mysqldのcopy_data_fromでテストが更に捗る話 »

2013年6月23日

CPANで意図しない名前空間の取得を防ぐために

だいたいこのへんで教えてもらった話のまとめです。

http://lingr.com/room/perl_jp/archives/2013/04/03

CPANで名前空間を取るのは簡単です。今ならCPANに上げるコードベースの「どこか」に package Hoge; と書けば、CPAN Indexerにインデックスされていとも簡単にHoge名前空間のオーナーになれます。 (執筆時現在Hogeのオーナーはいません)

これはlib/以下の.pmファイルやファイル先頭のpackage宣言だけに限った話ではありません。 例えば、example/MyApp.pmとかも対象です。

ちなみに誰がどの名前空間を持っているかは以下を見ることでわかります。

http://www.cpan.org/modules/02packages.details.txt

多くの場合この挙動に困ることはありませんが、以下の様な場合に困ることがあります。

  1. example codeを同梱してその中にpackage宣言を含む場合 eg. package ExampleApplication;
  2. 自分が持っていない他人の名前空間のpackage宣言をする場合 eg. package Plack;

1の場合は、特に欲しくもないExampleApplicationという名前空間を取得してしまいま す。あまりかっこよくありませんし、もし他の人がその名前空間を欲しがったら困るでしょう。

つい最近だと、Mozilla::DOMのexampleにMinilla.pmが同梱されていて、名前空間がす でに取られていたので、Minillaでは交渉して名前空間を開けてもらったみたいな話もあったりし ました。

2の場合は「権限のない名前空間を取ろうとするんじゃねーよ!」ってCPAN Indexerに怒られます。 そして無常にも ** UNAUTHORIZED RELEASE ** の烙印を押されます。

そういうことを起こさないために以下のような対応が必要です。

  • 適切にnoindexを設定する、またはnoindexをケアしてくれるauthorizing toolを使う
  • packageの後に改行を入れる # hide from PAUSE ハックを使う(あまりやるべきではない)

適切にno_indexを設定する、またはno_indexをケアしてくれるauthorizing toolを使う

CPAN::Meta::Specのno_indexの項 に書いてあるように、インデックスしてほしくない項目をno_indexで指定することができます。 Makefile.PLやBuild.PLに適切な設定項目があります。

一応、t/やinc/などはIndexerはskipしてくれるようになっていますが、そういう挙動 に期待せずに、ちゃんと指定した方が良いです。

また、MinillaやMillaだと、

directory => ['t', 'xt', 'inc', 'share', 'eg', 'examples', 'author']

を自動的にno_indexに追加してくれているので、その辺気にしなくて良いので楽チンです。

packageの後に改行を入れる # hide from PAUSE ハックを使う(あまりやるべきではない)

他人のモジュールに対して、モンキーパッチしたいとか、メソッドを追加したいそうい うそもそもお行儀の良くない要件がごくたまにありますが、そういう時に、素直 にpackage宣言を書いてしまうと、名前空間を取ろうとしてしまうので良くありません。

そういう時は以下のように改行とコメントを入れることでインデックスをさせないこと が可能です。

package # hide from PAUSE
    Plack;

こういう他人のモジュールに動的に手を入れたいという要件の時のみに使うべきで、 そもそもそういうお行儀の良くないことはあまりやらないほうがいいでしょう。

逆に、ファイルの先頭に書かないinner packageなどで、package宣言の後に改行を入れて しまっているケースをたまに見かけますがこれはあまり良くありません。

なぜかというと、サブパッケージであっても、その名前空間を取得しておかないと、 他の人にその名前空間を取られてしまうかもしれなくて悲しいからです。


余談ですが、CPANモジュールはlib/ 以下にモジュールを配置するのが一般的な形ですが、 あくまで慣例であって、別にそう決まっているわけではありません。 また、Inner Packageなどもあるので、ファイル名とパッケージ名が一対一対応しているとも 限りません。

なので涙ぐましいパース処理をIndexerは行なっています。

その様子は https://github.com/andk/pause/tree/master/lib/PAUSE 辺りのソース を読むと良いでしょう。

投稿者 Songmu : 2013年6月23日 02:02