« 2013年4月 | メイン | 2013年6月 »

2013年5月27日

Cache::Redisってのを書いたら意外と大変だった件

最近Redis使うのは当たり前で、開発とかテストでmemcachedすら立てるのめんどくさくて、なるべくRedisに寄せたいと思っている。

セッションストレージもRedisで良くねって思って、ArkだとCache::Cacheなインターフェースのモジュールがあれば簡単にセッションストレージを差し替えられるようになっているので、Cache::Redisってのを書いた。

先のエントリーでも書いたとおり データに対するメタ情報をRedisの場合もたせられないので、[$data, $flags] って データを作ってそれ毎まるっとシリアライズするという乱暴な作りになっている。

なので、ストアされているデータをredis-cliとかで読もうとしても読めないのが難点。

redis-cliで読めるように値をRedisのリスト型にして持たせることも検討したけど、普通に setする場合と比べて大分遅くなってしまったのでとりあえずやめた。

シリアライザにMessagePackも指定できるようにはしてあるけどStorableと比べて全 然速度差が出なかったり、今のところutf8決め打ちだったりするのでこの辺も変わりそう。

バックエンドは色々検討した末にRedis.pmになってる。再接続のケアとかがしっかりし てるのが現状の決め手。

Redis::hiredis使おうかと思って、いくつかp-rを送って取り込んでもらったりもしたんだけど、 いかんせん(当然ながら)プリミティブな実装なので、再接続とかその辺のケアをしてくれる ラッパーモジュールを書かないと厳しそう。

ただ、やっぱRedis::hiredisは大分高速で、単純に差し替えてベンチを取った場合、 3倍近く速くなる。そうなるとCache::Memcached::Fastには及ばないまでも遜色ない感 じにはなるので、出来れば差し替えたいなーとは思っている。

現状開発では使っているけど、実サービスでは使っていません。なのでインターフェース は変わらないと思うけど裏側は結構変わると思うので、使っている人がいたら注意して下さい。

フィードバックいただけると嬉しいです。

00:47

2013年5月26日

memcachedのflagsってのが何のためにあるのかっていう話

memcachedで値をセットするときに以下みたいな感じでセットするわけですが、 この<flags>ってのが何のためにあるのかいまいちよくわかってなかったわけです。

set <key> <flags> <exptime> <bytes>
<data>

で、Cache::Redis書いてた時にCache::Memcached::Fastの実装を見てたら、 あーこれ大事だわってなった。C::M::Fだと、ストアされているデータが

  • シリアライズされてるか否か
  • 圧縮されてるか否か
  • 文字列か否か

みたいな情報をこのflagsに持たせています。

C::M::Fはオブジェクトやリファレンスはシリアライズして、 単一スカラ(数値や文字列やバイナリ)はシリアライズせずに値をストアするように なってます。これはデフォルトのシリアライザであるStorableが単一スカラをシリアラ イズできないというのもありますし、単一スカラであればシリアライズしないほうが 情報が人間に読みやすいってのもありそうです。

その場合、例えばシリアライザがStorableの場合だと、memcachedから値を取得してき た値がバイナリだった場合、それはシリアライズした結果バイナリなったものなのか それとも、元からバイナリデータが突っ込まれていたのかがその値だけでは判別出来ません。 そこでflagsを見て判断するようになってるわけです。(具体的には0x1との論理積をとっている)

もう一つ例を出すと、シリアライザがJSONの場合、[1]っていうデータが入っていた として、それが配列なのか、文字列としての’[1]’なのかがそれだけだとわからないって話です。

一定サイズ以上の文字列を圧縮してストアするみたいなことも、C::M::Fはできるよう になっているので、そのへんの判別もflagsを見てやるようになっています。

値に対する最低限のメタ情報を値とは別に持たせられるようにしてあるのは 実用性を考えたいい設計だなーと思ったわけです。

Redisの場合だとそういう値とは別のメタ情報をもたせられるようにはなってないので (もちろんやりようは色々あるわけですが)、Cache::Redisを書く際にちょっと苦労した という話。その辺の話は次のエントリーで書きます。

23:49

2013年5月24日

Params::TinyとHash::MultiValue、もしくは本物のTinyについて

tl;dr

  • Params::Tinyってのを書いた
  • 驚きのTiny
  • ニーズ無さそう
  • Hash::MultiValueがparamメソッド持ってれば良くね?ってなったけど、Requestクラスじゃない単なるデータコンテナクラスがそういうの持ってるの微妙なのかなー?ってなってる

本題

旧来からPerlにおいて、古くはCGI.pm、最近ではPlack::Requestまで、Requestオブジェクト 的なやつは $req->param が呼び出せることが期待されておりました。

なので、FormValidator的なモジュールはCGIが来ようがCatalyst::Requestが来ようがPlack::Request が来ようが値の検証が行えておりました。Duck typing的なあれです。

しかし逆に、単にハッシュとかからサクッとparamの生えてるオブジェクトを作るのは 大変というか、ニーズもないし逆に簡単すぎるので、誰もあんまそういうモジュールを 作ったり使ってこなかったのだと思います。一応、 Class::Paramってのはあるようです。

たまーにそういうの欲しいなーって思うことはあるんですが、だいたいテスト用の モックだかスタブだかで欲しいだけなので、CGI->newで良いかってなるわけです。

ただ、今回FormValidator::Liteにハッシュ渡したいみたいな要件があったみたいで、 じゃあなんかそういうブリッジをするやつを書いてもいいのかなーと思ったら、 驚くほどのTinyコードになった。予想はしてた。 Hash::MultiValue継承してparamメソッド追加しただけ。

こういうのって、CGI.pmぽいコンテキスト見るparamメソッドになってるのが良いのか なーと思ったので、Hash::MultiValue使っててPlack::Requestと同じような感じになってる。その辺の話は このへん

結局Yoshina::Validatorみたいなのをsoh335先生が作るってことで落ち着いた。別にこ のコード使われると思ってなかったし、使おうとも思ってなかった。

Hash::MultiValueにparamメソッド生えててもいいのかもなー、でも微妙だしそもそも ニーズ無いけど、たまに欲しいしなーとか思った。

ぼくはこう思う

コード書くよりこのエントリー書くのに何十倍も時間かかってる。

22:27

2013年5月21日

Perl製のWebアプリケーションをherokuで3分で動かすの法

PSGIアプリなら簡単にherokuで動かせます。

Miyagawaさんのbuildpack(https://github.com/miyagawa/heroku-buildpack-perl)を 使います。使い方もREADMEに書いてあったけど、以下にも書きます。

アプリ側の準備

deployしたいアプリケーションのgitリポジトリ上で以下をやります。

  • cpanm --installdeps . で依存モジュールがちゃんと入るようにする(cpanfile使うのがオススメ)
  • アプリ起動用のapp.psgiを配置する

herokuにアカウントを作る

https://www.heroku.com/

toolbeltを入れる

https://toolbelt.heroku.com/

インストールが終わるとherokuコマンドが使えるようになります。

% heroku login と打ってコマンドライン上でherokuにログインします。(鍵の登録とかよしなにやってくれる)

アプリを登録する

gitリポジトリ上で以下のように打って登録します。

% heroku create appname --buildpack https://github.com/miyagawa/heroku-buildpack-perl.git

ここの、”appname”がherokuappのサブドメインとしてグローバルに登録されるので注意。どういうことかと いうと、僕が % heroku create ukigumo とかやったら、http://ukigumo.herokuapp.comがしれっと 取れてしまいました。

—buildpackの指定が面倒くさくて、「オレはperlでしかherokuに上げないぜ!」って いう強者は以下のようにすれば、defaultのbuildpackを指定できる模様。

% heroku config:set BUILDPACK_URL=https://github.com/miyagawa/heroku-buildpack-perl.git

アプリをデプロイする

先ほどのコマンドで、gitのherokuのremote repositoryが追加されています。そこにgit pushすれば commit hookが走ってアプリがデプロイされるオシャレ仕様。

% git push heroku master

enjoy!

落穂広い

動作環境は?

system perlの5.10でapp serverはStarmanです。

任意のバージョンのPerlを使えるようにするみたいな案はあって、issueは上がっています。

https://github.com/miyagawa/heroku-buildpack-perl/issues/3

上のissueでは参考例としてNodeが上がっていますが、これは他のEC2のインスタンスでコンパイル したバイナリを使うというかなり強引で頑張った作りになっているようです。

誰か頑張ってみてください。

お金かからないの?

単一アプリケーションを何のオプションも無く動かた場合は、ギリギリ無料範囲に収ま るようになっているみたいです。以下の資料が参考になりました。

http://www.slideshare.net/shunjikonishi/heroku-15670119

22:59

2013年5月19日

ジンバブエドルとギャンブルに関するお役立ち情報です

紙くず同然に思われがちなジンバブエドルですが、2009年に

  • 12桁のデノミ(旧1兆ジンバブエドル=1ジンバブエドル)を行った
  • 発行自体も止めた(=ハイパーインフレが止まった)

という感じなので、今は実はレートはそんなに低くありません。

発行が止まり、ジンバブエの公式通貨でもなくなっていて、死にゆくことが約束されている通貨ではありますが、通貨価値が消滅したわけではなく、一部の地域で使えはするようです。

具体的には、2013年5月現在1ジンバブエドル=0.3円程度のレートとなっています。これは多くの人に取って意外な数字なのではないでしょうか。ついうっかり1億ジンバブエドルを賭けて負けてしまうと3000万円の損失です。

入手も困難ですし、使える地域も限られているという意味ではやはり紙くず同然なので、安易に多額のジンバブエドルを賭けるのは危険ですし、賭けに勝った方もやはり嬉しくないので、皆様注意しましょう。「ペリカ」や「ガバス」を使うのが安全かと思います。

20:57

2013年5月16日

Perlの引数の渡し方の想像上の歴史

一般的な以下の様な渡し方について。

  1. func($foo, $bar);
  2. func({foo => $foo, bar => $bar});
  3. func(foo => $foo, bar => $bar);

昔は1だったけど、2って書けるのも分かりやすくて良くね?ってなって、1でも2でも指定できるような書き方が出てくるようになった。

だんだんこの場合は1にすべき2にすべきっていう住み分けができてきて、両方の指定ができるみたいなのが減ってきた代わりに、じゃあ3の書き方で良くね?ってなってきた。今度は、2でも3でも指定できるみたいな書き方が出てくるようになった。

僕は最近は3決め打ちで良くね?って感じてきている。MouseとData::Validatorを便利に使わせてもらってるんで結果的には両方いける感じになっていることが多いけど。

値をhashに詰めるのとhashrefに詰めるのどっちが好きかって好みの問題もありそうではある。僕はタイプ数が減らせるし、なるべくhash使いたい派。逆に色々sigil使いたくないって人はなるべくhashrefに統一するのもひとつの手だとは思う。

2だと参照渡しになる分若干早くなるのかもしれないけど、逆に意図せず値が書き換わるリスクがある。事前に値をhashrefに詰めておいて、後でガバッとメソッドに渡すやり方をするとそういうバグが起きやくすくなる印象。

3だと順番も保持されるし同じキーを複数回指定するみたいなのもハンドリングしようと思えば可能なのも良い感じ。

1の使いどころも勿論あって、引数が1つか2つで明らかにそういう渡され方をするってのが客観的にも自明であれば使ってもいいと思う。その場合英語的に自然かどうかってのも大事な判断材料だと思っている。 $s->v($o, $c); みたいな。

英語に自信がないのであれば(僕もない!)、引数が少なくても迷わず3の形の名前付き引数を採用するのが安全かなーと思います。

【追記】

fujiwaraさんの体感値だと、

func($foo, $bar) -> func( foo => $foo, bar => $bar ) -> func({ foo => $foo, bar => $bar })

の順で見かけるようになったとのことです。確かに、perl4の時代はHashRefとかなかったので、Hash渡ししかできません。実際、歴史あるCGIモジュールはHash渡しになってます。

https://metacpan.org/module/CGI#SYNOPSIS

  • Catalist, DBIC辺りから、HashRef渡しをよく見るようになった
  • 最初はhash直で、その後hashref渡しが流行って でもぜんぶhashrefって微妙じゃね、ってなって揺り戻しが来てる感じかなあ

というお話で、そっちの方が正しい感じがします!

02:12

2013年5月14日

CSRFDefender的なやつでコンテンツフィルタはしないほうがいいんじゃないかという話

本日の組長のお話。

Ark::Plugin::CSRFDfenderに機能追加したりいろいろバグっていたりしたのに手を入れていたのだが、それに対して組長に意見を頂いた話。結論はタイトルの通り。

CSRF対策をフレームワーク側で入れるのは良いと思うが、フィルタしてformに自動的にhiddenを埋め込むのはあんまよろしくないんじゃないかという話です。

CSRFDefender的なやつには以下のような機能があるが、それぞれに関して述べる。

  • POST, PUT, DELETE時に自動でtokenチェックしてエラー画面強制表示
  • 自動的にコンテンツフィルタしてform要素にhiddenを埋め込む

POST, PUT, DELETE時に自動でtokenチェックしてエラー画面強制表示

OK。安全側に倒している。

自動的にコンテンツフィルタしてform要素にhiddenを埋め込む

あまり好ましくない。厳密に安全側に倒すのが難しい。

例えば、formのaction要素に外部URLが入っていた場合に簡単にtokenが外部サイトに漏洩してしまう危険性がある。(例えば検索窓など)

  • methodがGETのフォームはフレームワーク側でフィルタしない
  • 外部URLに直接POST指定とかするな!

という話ではあるが、意図しない使い方をされることで逆に危険になるような設計は好ましくない。

form.actionはJSで上書きもできてしまうので、フィルタ処理側でそのformがhiddenを埋め込むべきか否かを厳密に判断するのは実質不可能に近い。

どうするのが良いのか?

自動tokenチェックをしてCSRFエラー画面で「あなたの予想に反して、このページが見えているでしょうか?」的なことと対応ガイドラインが表示されるようになっていれば、hidden漏れに開発時に気づける。ので、開発者が手でhiddenを都度埋め込めば良い。そのためのヘルパー関数をpluginが準備しておくのも良いと思います。

コンテンツフィルタ機能は便利っちゃあ便利なので、リスクを承知した上で、その機能 をオンできるようになっているのは有りだとは思いますが、デフォルトでその挙動になってるのは危ないんじゃでしょうか。

Ark::Plugin::CSRFDefenderは非互換にはなりますがその方向で修正する予定です。

余談ですが、csrf_tokenはsession_idで十分だという話もあったりますが、上記のように漏洩リスクがあるので、session_idを元にハッシュ化したものをtokenにしたりする方が良いのかなとかなんとなく思いました。

【追記】tokuhiromにそもそも漏れても問題ないようなtokenを使ったほうが良いんじゃないかという指摘をもらいました。それならば、自動的にコンテンツフィルタを入れていて、tokenが漏れたとしても大きな問題にならないので。こういう機能において、漏れては困るようなtokenを埋める処理を入れるのが筋悪って話ですね。

結論

めんどうくさいWebセキュリティ

18:43

2013年5月12日

最近のModule::InstallでTravisるときのポイント 2013年5月度版

tl;dr

  1. Module::Install::CPANfile を使う
  2. cpanfileのon ‘develop’セクションにModule::Install関連の依存を記述する
  3. .travis.ymlにinstall: cpanm --with-develop --installdeps --notest .を書く

あらすじ

最近のModule::InstallでTravisるときの注意ポイント ってのがあるが、折角DSLなのに、BEGINに色々書くのは悲しかったが、今はcpanfileがあるので、Module::Install::CPANfileで解決できるよって話。

Module::Install::CPANfile を使う

依存関係をcpanfileに記述します。Makefile.PLからそのままコピペしてきて良いでしょう。featureとかはちょっと書き方が違ったりします。そもそもfeatureとかの扱いがどうなってるのかちょっと良くわからなかった。

Makefile.PLからは依存関係の記述を削除して、その代わりに

cpanfile;

と書きます。

cpanfileのon ‘develop’セクションにModule::Install関連の依存を記述する

cpanfileに以下のような記述を追加します。

on 'develop' => sub {
    requires 'Module::Install';
    requires 'Module::Install::CPANfile';
    requires 'Module::Install::AuthorTests';
    requires 'Module::Install::Repository';
};

.travis.ymlにinstall: cpanm --with-develop --installdeps --notest .を書く

cpanmのオプションに—with-developを渡すと、cpanfileのon ‘develop’のモジュールもインストールしてくれます。travisのデフォルトだと—with-developはついていないので、.travis.ymlで設定を上書きしてやればok。

最小の.travis.ymlは以下の通り。

language: "perl"
install: cpanm --with-develop --installdeps --notest .

これでok。Happy travis life!

落穂拾い

なんでon configureじゃなくてon developなの?

M::Iはinc/に同梱するものなので、ユーザーにon configureでインストールさせるのはおかしいですねって話です。

あと、on configureだと—installdepsで入れてくれなかったりしたのと、—with-configureみたいなオプションも無いってのもある。(この辺深く追ってない)

元のハックと比べるとgit repoからモジュールをインストールしようとした時のエラーメッセージがわかりづらくなるんだけど?

仕方ないので諦めましょう。

Module::Install をつかっているモジュールを git からインストールできるようにするためのパッチ」、みたいな話もあったみたいですが、ちょっとその後どういう決着になったのかちょっとよくわかってない。

結論

cpanfile、cpanm周りはまだまだ流動的なのでベタープラクティスは変動していくと思うし、今回の記事も怪しい部分がある気がしているので、フィードバックあると嬉しいです。

16:58

MySQLのsql-modeで一番厳しいやつはTRADITIONAL

このへんに書いてありました。

http://dev.mysql.com/doc/refman/5.5/en/server-sql-mode.html#sqlmode_traditional

なので、これを設定しておけば良いんじゃないですか。STRICT_TRANS_TABLESと大きく違うのは、日付周りをより厳密に処理してくれるようになる点ですね。

「えっDATETIME型使うの?」とか言われることもあるんですけど、MySQL shellで読みやすいし、partitioningしたときにpruningも効くしいいじゃないですかね。INT使うのとかだいぶバッドノウハウ感あるし。とか思ったら最近はTIMESTAMPでもちゃんとpruning効くっぽくて泣いてる。

‘TRADITONAL’なのに一番厳しいのがMySQLのゆるふわ感を醸し出していて良いですね。

03:44

DBD::mysqlでmysql_enable_utf8しつつutf8mb4使いたいとき

今のところの結論として、接続時に

SET NAMES utf8mb4;

するしか無いんじゃないかなーという感じがしている。SET NAMES使うのかよ!ってdisられそうで怖いです。

DBICやTengの場合はon_connect_do、生DBIやSunnyの場合はCallbacksで指定できます。

なんか、mysql_enable_utf8していると、DBD::mysqlがMYSQL_SET_CHARSET_NAMEでutf8に決め打ってしまうので、さらにSET NAMES utf8mb4して上書きしてやらないといけないという感じ。ソースとしては以下の辺り。

https://github.com/CaptTofu/DBD-mysql/blob/4_022/dbdimp.c#L1803-L1816

DBD::mysql側でなんか対応して欲しい気もするけどどうするのが綺麗なんでしょうかね。

ちなみに、あんま深追いしてないけど、SET CHARACTER SET utf8mb4 だとダメでした。

mysql_enable_utf8は未だexperimentalだけど皆使ってますよね。いちいちデータを全部文字列化するとかだいぶタルくてやってられないし絶対どこかで漏れて文字化けとか起きるし。

03:00

pullreqを別ブランチにマージしたいとかsquash mergeしたいとき

以下のようにして、git fetch-pullsを登録しておけばpullreqの内容を手元に持ってこれるので、手元でmergeしてpushすれば良い。

何らかの形でmergeさればpullreqも自動的に閉じるようになっています。(場合によってはcontributorにpullreqしてもらった人が表示されなくて悲しい思いをしたりはする)

pullreqを別ブランチにマージしたいケースとしては、例えば、failするテストケースだけをpullreqしてもらったりした場合に、それをmasterにcommitしたくないよね、的なやつです。

squash mergeとかも気にする人に対して、pullreq時に「commitまとめてくれ」とか言われたら「そっちでsquash mergeしてくれ」って言えるのが良いと思います。

なので、勿論限度はありますが、汚いcommit logのbranchからpullreq送っても良いし、コケるだけのテストケースをpullreqするのもいいんじゃねーのって話です。少なくとも僕はwelcomeです。

02:22

3分でpull request

サクッとpull requestを送るために。

tl;dr

  • % git config —global push.default simple しておく
  • ブラウザでfork押して、そのリポジトリをcloneする
  • % git checkout -b feature/hogehoge ってやってbranch作る
  • 変更してコミットする
  • % git push —set-upstream origin feature/hogehoge として修正をpushする
  • ブラウザからpull request

あらすじ

ikachanを導入しようとした所、AnySanがssl未対応だったのでpullreq送ろうとしたらすでに同僚のmix3先生がpullreqしていて、mix3++であった。しかし、masterブランチからpullreq送るのは良くないよねってことで練習のためにtopicブランチを切ってpullreqを送り直してもらうなどした。早く取り込まれるといいね。

以下説明。

% git config —global push.default simple

本題とはあまり関係ないんですけど、この設定をしておくと % git push したときに分かりづらい挙動にならないので設定しておくと良いと思います。Git2.0からはこの動きがdefaultになるようです。

ブラウザでforkしてそのリポジトリをcloneする

そのまんまですね。以前forkしていてそのリポジトリが古くなってた場合は追随する方法もありますが、わからない場合は消してforkし直しましょう。

% git checkout -b feature/hogehoge ってやってbranch作る

masterで作業せずにすぐブランチを切ります。branch名は、機能追加はfeature/、ドキュメンテーションはdoc/、バグフィクスはfix/とかつけておくとわかりやすくて良いんじゃないかと最近思っております。

変更してコミットする

なるべく1commitにまとめましょう。少なくとも、作業の試行錯誤が見えるような汚いcommit logを残さないように。

コミットメッセージはなるべく英語で書きましょう。

% git push origin feature/hogehoge として修正をpushする

ここでおもむろに % git push とかすると以下の様なエラーが出ます。

[Songmu]$ git push
fatal: The current branch feature/hogehoge has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin feature/hogehoge

% git push —set-upstream origin feature/hogehoge するといいよ!て書いてあるのでありがたくコピペして実行するとちゃんとリモートブランチが作られます。

ブラウザからpull request

そのまんま。これもまたなるべく英語でメッセージを書きましょう。相手が日本人でも、なるべく公開の場では英語でやり取りして、IRCとかで日本語で相談するのがいいんじゃないかなーと最近思います。

あとはmergeされるのを待ちましょう。残念ながらrejectされてしまうこともあるかもしれませんがめげないで頑張りましょう。

落穂拾い

pullreq後、作者から修正要望がついた場合は?

修正内容をブランチにcommitしてpushすれば大丈夫です。もう、ブランチからオプション無しのgit pushするだけでremoteに反映されるようになっています。

pullreqがmergeされるなり決着がついた場合は?

今後あまり継続的にpullreqを送らないのであれば、forkしたリポジトリを消してしまっても良いでしょう。しばらくたってpullreqを送りたくなったらまたforkすれば良いのです。

今後もforkしたリポジトリを本体に追随させていきたい場合は?

fork元のオリジナルのリポジトリを登録する。

% git remote add upstream git://github.com/...

masterブランチで定期的に追随して自分のリモートにもpushする。

% git checkout master
% git pull upstream master
% git push
複数の機能や項目をpullreqしたい場合は?

個別にブランチを切って、別々にpullreqを送りましょう。

pull requestが取り込まれる前にその機能を使いたい場合は?

複数pullreqを送っていてその両方の機能を手元では使いたいとかそういう場合は、oreoreブランチを作ってそこにbranchを両方マージして使ったりしています。

01:47

2013年5月 4日

Config::PLというのを書きました

https://metacpan.org/module/Config::PL

.plファイルを設定ファイルとして使う時のユーティリティです。以下の様な感じで使えます。

use Config::PL;
my $config = config_do 'config.pl';

do 'config.pl'のハマりどころや不便な点を解消しています。doの問題点は具体的には以下の様な点。

  1. config.plにsyntax errorがあってもエラーにならない
  2. 絶対パスで指定しないと危ない。doはモジュール読み込みと同じルールでファイルを探しに行くので、@INCを探しにいってしまう。config.plが@INCに置かれているとそっちが優先的に呼ばれる(!)
  3. config.plから他のファイルを相対パスで読み込めない

これらに対してConfig::PLは、

  1. syntax errorやhashrefを返していない場合にエラーになる
  2. @INCをlocalizeして、cwdとそのファイル自身がおいてあるディレクトリしか探さない
  3. そのファイル自身が置いてあるディレクトリをlocalizeした@INCに含むので、相対パスで読み込み可能

というようになっています。

設定ファイルが置いてあるディレクトリで、同じディレクトリにある他のファイルを環境変数に応じて読み込みたい時なんかに便利で、

以下の様な構成になっている時に、

[songmu@localhost]$ ls config
common.pl  development.pl  production.pl  test.pl

例えばこのような感じで環境変数に応じた設定の切り替えが可能です。

# config/common.pl
use Config::PL;
config_do "$ENV{PLACK_ENV}.pl";

以下のように書くよりわかりやすくていいんじゃないかと思います。

use File::Spec;
use File::Basename;
do File::Spec->catfile(File::Basename::dirname(__FILE__), "$EVN{PLACK_ENV}.pl")

環境変数に応じた設定に切り替えに関しては@cho45氏のConfig::ENVが非常に便利ですが、Config::ENVの作法を覚えないといけなかったりするので、もう少し通常の作法に近い解決方法をサポートしようと思い、書いてみました。普段使っているArkが、config(?:_local)?.pl 決め打ちだってのもあります。

同様のモジュールとして、これもまた@cho45氏のConfig::Doってのがありましたが、これはconfig.plにエラーがあった場合ににエラー終了することを保証するもので、Config::PLのように@INCをlocalizeするようなお節介をしないところが異なります。

依存もないので簡単にお使いいただけます。お試しください。

11:54