D-7 <altijd in beweging>

Day to day life of a Perl/Go/C/C++/whatever hacker. May include anything from tech, food, and family.

タグ:Perl

Text::Xslate is one of the latest inventions by Goro Fuji. It's yet another template engine -- and since it is yet another template engine, I could easily see everybody going "oh, *another* one....". Yeah, I get the idea. I feel the same for most new template engines.

But I have to say, this time... this one /is/ worth looking at.

First off, it's blazing fast. For trivial tasks, Text::Xslate (ex-slate) is 10 ~ 20 times faster than Template::Toolkit. Check out some of the benchmark scripts in the benchmark directory.

For example, here's demo-tt.pl ran on my Mac OS X:

daisuke@beefcake p5-Text-Xslate$ perl benchmark/demo-tt.pl 
Perl/5.12.1 darwin-2level
Text::Xslate/0.1030
Template/2.22
Template-Toolkit's process() x 1000
1000
Used: 3.457 sec.
Text::Xslate's render() x 1000
1000
Used: 0.207 sec.
In this benchmark, Xslate is about 16.7 times faster than Template-Tookit.

Now usually that kind of speed comes with a significant hit on the template language's usability. 

For example, templates like Mason or Text::MicroTemplate allows you to write raw Perl -- which /is/ good in some situations, but in my line of work, you need a moderately easy language for designers to work on. You can't quite expect designers to be able to decipher Perl code in the templates.

The really cool thing about Text::Xslate is that now it supports a 80 ~ 90% Template-Toolkit compatible template language, with all the variable methods and what not. I just switched my Template::Toolkit based Catalyst app to Text::Xslate with only minor changes in the template -- it was an easy task. And now the template rendering is blazing fast!

To use Text::Xslate in a sort-of-TT-compatible mode, do the following:
use strict;
use Text::Xslate;

my $xslate = Text::Xslate->new(
    syntax => "TTerse",
    module => [
        'Text::Xslate::Bridge::TT2Like',
        # or 'Text::Xslate::Bridge::TT2'
    ]
);
print $xslate->render_string( <<EOT, { foo=> "bar" } );
The value of foo is '[% foo %]'
Its length is [% foo.length() %]
If I perform s/foo/bar/, it becomes [% foo.replace('foo', 'bar') %]
EOT

The use of "TTerse" enables the use of TT compatible template tokens ('[%', '%]'), and enables TT like syntax like WRAPPER, INCLUDE, FOREACH, WHILE, SET, etc. DEFAULT and PROCESS are not supported, but from what I can tell you can live with it.

If you suspect you might have some performance bottleneck in your template rendering, I suggest you seriously consider this template engine. If you are a Catalyst-head like me, you can use my Catalyst::View::Xslate to easily integrate Text::Xslate and Catalyst.


Happy Xslate-ing!
    このエントリーをはてなブックマークに追加 mixiチェック

Web+DB Press vol.56でAnyEvent入門記事を書きました。

いつも使うわけではないだろうけれども、これからはイベント駆動、非同期処理はサーバーサイドのエンジニアには必須なツールの一つになっていくと思います。

AnyEventを使うと簡単に非同期処理が手軽に書けるので、興味のあるかたは是非確認してみてください!
    このエントリーをはてなブックマークに追加 mixiチェック

perl-casual #02 でライブコーディングしてきましたよ

伝わったかどうか自信がないけど、あの中で分かって欲しかったのは

  • CPANに色々あります
  • 無限の組み合わせこそがPerlの強み
  • 自分の環境にperldocっていうすげぇツールがついてるからうまく利用!
  • 英語のドキュメントにびびらないで!ほとんどのモジュールはかなり質の高いドキュメントがついているから賢く検索してみて!(関数名、キーワード、"return")

というあたりかな。Perlは怖くないよ!





あとはこちらは半分冗談ですが「IDEなんていらねぇよ。vimで十分」というのも昨日垣間見えたのではないかな!w
    このエントリーをはてなブックマークに追加 mixiチェック

*追記有り。

今Markdownで紙用の原稿書いているんだけど・・・

Markdownって楽だけど、実際にフォーマッティングがどんな感じになるかを見るには1回パースして処理する必要があるじゃないですか。いちいちMarkdown.pl呼び出すのも面倒くさいからPlackでディレクトリ直下のファイルをパースしてはき出すようにした。

Plackはなにげにこういう使い方が異常に便利な気がする。まさにSwiss Army Knifeって感じ。
use strict;
use File::Spec;
use Text::MultiMarkdown 'markdown';

sub {
    my $env = shift;

    my $file = File::Spec->catfile(
         File::Spec->curdir, $env->{PATH_INFO});
    open my $fh, '<', $file or die "Failed to open $file: $!";

    [ 
        200, 
        [ "Content-Type" => 'text/html; charset=utf-8' ],
        [
            <<EOM,
<html>
<head>
    <style type="text/css">
    <!--
        body {
            font-family: Halvetica, sans-serif;
            padding-left: 2em;
        }
        pre { padding-left: 2em }
    -->
    </style>
</head>
<body>
EOM
            markdown(do { local $/; <$fh> }), 
            <<EOM,
</body>
</html>
EOM
        ]   
    ]   
};

*追記

全く持ってめんどくせぇけど、PHPのほうがいいじゃないか、ってのはすげぇ違うので一応書いておく。


まず誤解を生まないように書くと、CGI環境で動くようなのもText::MultiMarkdownさえ動く環境ならどこでもすぐできますし、Plackがあろうとなかろうとら昔からこれくらいできますね。

でもCGIだとこれをサーバーにアップロードしないといけないじゃない。俺はローカルディスクに入ってるファイルをちょこちょこ見ながら編集したいだけなんだよね。だから書いたの。というわけでPHPだから云々は話が違う。「RoRだったら・・・」だったら分かるけど。


ついでなのでPlack版も組み替えましたよ。別に汚くてもリリースするわけじゃないし、いずれにせよ5分で実用的なものがかけたからいいと思うけどね。ちなみにpsgiじゃなくてもPlack::App::WrapCGI使えばさっきのCGIファイル使えるよ!(自分もそれでテストしたのに忘れてた)

    このエントリーをはてなブックマークに追加 mixiチェック

Test::More 0.94からsubtest()ってのが使えるので、Any::Mooseみたいな根本的な切り替えが入っちゃうコードの検証に、こんなテストが書けることに今日気づいた。

use strict;
use Test::More;

local $ENV{ANY_MOOSE} = 'Moose';

my @files = ;
plan tests => scalar @files + 1;

while (my $file = shift @files) {
    subtest $file => sub { do $file };
}

ok( Any::Moose::moose_is_preferred() );

Data::Localize 0.00013 に入れた。
    このエントリーをはてなブックマークに追加 mixiチェック

まだちゃんと使ってないから問題点とかわからないけど、とりあえずStarmanを使うとかで結構スケールできる気がする。そのあたりを自由に変えられるのもPlack++だね。

使用想定としては、これをplackupしておいて、クライアント AnyEvent::HTTPで http_postして非同期で応答待ちする感じ。

package Lyra::Server::Worker;
use Moose;
use Router::Simple;
use JSON::XS;
use namespace::autoclean;

use constant NO_SUCH_WORKER =>
    [ 404, [ "Content-Type" => "application/json" ],
        [ q|{ "status" => 0, "message" => "no such worker" }| ] ];
use constant BAD_PAYLOAD =>
    [ 500, [ "Content-Type" => "application/json" ],
        [ q|{ "status" => 0, "message" => "bad payload" }| ] ];
use constant WORKER_ERROR =>
    [ 500, [ "Content-Type" => "application/json" ],
        [ q|{ "status" => 0, "message" => "worker error" }| ] ];
use constant WORKER_SUCCESS =>
    [ 200, [ "Content-Type" => "application/json" ],
        [ q|{ "status" => 1 }| ] ];

has router => (
    is => 'ro',
    isa => 'Router::Simple',
    default => sub { Router::Simple->new() }
);

sub register {
    my ($self, $path, $worker, $method) = @_;
    $method ||= 'process';
    $self->router->connect( $path, { controller => $worker, action => $method } );
}

sub psgi_app {
    my $self = shift;
    return sub {
        $self->process(@_);
    }
}

sub process {
    my ($self, $env) = @_;

    my $matched = $self->router->match( $env );
    if (! $matched) {
        return NO_SUCH_WORKER;
    }

    my $payload;
    eval {
        $payload = $self->fetch_payload( $env );
    };
    if ($@) {
        warn $@;
        return BAD_PAYLOAD;
    }

    my $response;
    eval {
        my $worker = $matched->{controller};
        my $method = $matched->{action};
        $response = $worker->$method( $payload );
    };
    if ($@) {
        warn $@;
        return WORKER_ERROR;
    }

    if (! $response ) {
        $response = WORKER_SUCCESS;
    }

    return $response;
}

sub fetch_payload {
    my ($self, $env) = @_;

    if ($env->{REQUEST_METHOD} ne 'POST') {
        return;
    }

    my $cl = $env->{ CONTENT_LENGTH };
    my $ct = $env->{ CONTENT_TYPE };

    # $ct should be application/json, but we're not checking this right now

    my $input = $env->{ 'psgi.input' };

    # Just in case if input is read by middleware/apps beforehand
    $input->seek(0, 0);

    my $buffer = '';
    my $spin = 0;
    while ($cl > 0) {
        $input->read(my $chunk, $cl < 8192 ? $cl : 8192);
        my $read = length $chunk;
        $cl -= $read;
        $buffer .= $chunk;
        if ($read == 0 && $spin++ > 2000) {
            Carp::croak "Bad Content-Length: maybe client disconnect? ($cl bytes remaining)";
        }
    }

    decode_json $buffer;
}

__PACKAGE__->meta->make_immutable();

1;
    このエントリーをはてなブックマークに追加 mixiチェック

JPAでやんなきゃいけない事、手伝って欲しいことがいっぱいあるのでとりあえずメモ

  • 2010年度マニフェスト的なものを書かないといけないかなぁ。
  • JPAの日常業務をボランティアで手伝ってもらえる人を募集したい。メールへの反応、YAPC準備、研修準備。毎回お願いしてると結局俺がボトルネックになるので、ボランティアチームがいたらすごい嬉しい。特にYAPCは俺は前線に*出てはいけない*。YAPCで目立ちたい!人が前線に出るべき。LLにならってブレストをやったら人来るかな?
  • JPA PressがGoogle 検索に表れないので、どうにかする必要あり。この間のヤツからAdobeなんちゃらに文字データを入れ込んだはずなんだけど、検索にでてこないんだよな。どうすればいいの?
  • TPF本家ともっと緊密に行動する。特にGrantは使えると思う。ドキュメンテーション回りを特にどうにかしたい。

こっから下はまだ希望の段階。

  • 希望: どこかの大学・専門学校でPerlを教えているところと連携。ツテがあまりありませんので、連絡してもらえると嬉しい。
  • 希望: 全然声を掛けてないけど、なんらかの枠でDBI/Devel::NYTProfの作者のTim Bunce氏をYAPCに呼べたらなーと思ってるんだけど、ぶっちゃけ予算がありません。旅費をスポンサーしてもいいという企業・個人の方はいませんか。
  • 希望: 北海道・東北エリアでの Perl Mongerグループの創設。MLとかそういうのは別口でやってもらうにしても、PMのページをJPAで持つのはありかなぁ。
  • 希望: JPA会員だよ!ってな感じのブログパーツを作成したい。これもぶっちゃけ今は予算がないので、できればボランティアでお願いしたい。
    このエントリーをはてなブックマークに追加 mixiチェック

まだこう、細かいpros/consがわからないのでなんとも言えないんだけど、とりあえずaio_open/aio_writeと普通のopen/print/closeで同じ事した場合とでベンチマークとか取ってみた。これでいいのかなー

環境はMac OS X 10.5.8, 2.4 GHz Intel Core 2 Duo, 4GM RAM.

Comparing with buffer size 10...
         Rate normal    aio
normal 80.0/s     --   -19%
aio    99.0/s    24%     --
Comparing with buffer size 100...
         Rate normal    aio
normal 80.0/s     --   -18%
aio    97.1/s    21%     --
Comparing with buffer size 1000...
         Rate normal    aio
normal 76.9/s     --   -13%
aio    88.5/s    15%     --
Comparing with buffer size 10000...
         Rate normal    aio
normal 52.4/s     --   -27%
aio    71.9/s    37%     --
Comparing with buffer size 100000...
         Rate normal    aio
normal 15.9/s     --   -63%
aio    42.7/s   169%     --

コードはこちら、githubで。
    このエントリーをはてなブックマークに追加 mixiチェック

前のエントリ書いたら宮川さんにオススメ方法を教えてもらった

http://twitter.com/miyagawa/status/10271128928
plackup \
      -L Shotgun
      -MPlack::App::WrapCGI
      -e 'Plack::App::WrapCGI->new(script => "/path/to/cgiscript.cgi")'

だそうです!これなら全ての要件を満たせるもよう!そしてapp.psgiを作る必要ありません。

今これやってみて一つだけ問題点。多分POD入りのCGIは動かない。それと、__DATA__は見てくれるけど、__END__があると動かない。__END__さっき簡単なパッチのpull requestを送っておきました!

なお、-L Shotgunを使うと CGIファイルの中身は実行時までコンパイルされないのでご注意(つまり、plackup -rもいらないってことですね)
    このエントリーをはてなブックマークに追加 mixiチェック

ちょっと案件で簡単なCGIスクリプトをを開発することになった。StarmanとかTwiggyでほとんど全て書いているのに今更CGIとかそういう突っ込みはとりあえずおいておいて・・・環境を作るのも面倒くさいし、簡単にサーバーを立ち上げたり落としたりしたい。

そこでPlackです!

追記:その後もらったコメントによると、こちらのほうがよさそうです







具体的にはplackupとCGI::Emulate::PSGIを使います。

何も考えずにとりあえず開発したいので、以下のようにapp.psgiにコードを書いていく。
use strict;
use CGI::Emulate::PSGI;
return CGI::Emulate::PSGI->handler(sub {
    CGI::initialize_globals(); # 重要
# ここから
#!/usr/bin/env perl
use strict;
use warnings;
use CGI;
use CGI::Carp qw(fatalsToBrowser);

sub main {
    my $q = CGI->new();
    ....
}

main();

# ここまでがCGIのコード
});
あとで本当に単純にコピペしたいのでshebangもそのまま書いちゃうし、インデントもその部分だけファイルに書いたかのように記述していっちゃいます。

これを以下のように-rオプションをつけて起動。app.psgiのCGIコードに変更を加える度にサーバーも再起動して新しいコードを適用してくれる。
plackup -r -a app.psgi


これはいいわー。
    このエントリーをはてなブックマークに追加 mixiチェック

(はいはい、まず言語論争するつもりないから、そういうコメント禁止ね)

1. 論旨

新たな就職氷河期到来が叫ばれる昨今、就職に困っている学生さんもたくさんおろう。「技術があればチャンスはあるかも」って思う人もたくさんおろう。その際にプログラミングでもいっちょやってみっか、って思う人もたくさんおろう。

そこでとりあえず言語を選ぶよね。「就職を有利にするため」という条件をクリアするためにあなたなら何を選ぶ?Java? C#? Ruby? PHP? (ちなみに自分は大学を卒業した時点で一番得意だったのはJavaですよ)

色々選択肢はあるのは当たり前なので他の言語も排除はしないけど、僕としては自分の今持っている情報と経験から、Perlは覚えておいて損は全くない!と言い切れる。それは至極単純な理由で、需要より供給が圧倒的に少ないから。

就職情報サイトで一番多く当たる言語とかはもちろんそれだけ需要があるという事でもあるのは当然だけれども、それはつまり供給もほうも当然多いのです。競争も激しいし、当然ながら1人当たりの価値は下がります(この場合の価値というのは給料という意味ではなく、採用する企業側からみたあなたの価値.... 採用するときにどれだけハングリーな目で見てもらえるか、です)

JPAの会員になってくれてる企業のうちアクティブに採用を検討している会社は(採用基準も高いところも多いけれど)、それはそれは切実にPerlエンジニアをほしがってます。今から少しでも多くPerlの知識を身につけておけば、競争が比較的少ない分野で輝くことができる可能性が高いわけですよ。

あなたのゴールはなんですか?クールな言語を覚えること?流行物やバズワードに乗ること?それとも・・・仕事を見つけること?重要なのは採用してもらい、社会に出て、そこで経験を積むことなはず。

株式相場でもそうだけれども、勝ちたいなら基本的には逆張りしないといけないですよ。そういう意味で全く持って Perlは良いオプションだと思います。

ちなみに名の通ってるPerlを使用している企業の中ではWeb系の企業が多いのでPerlを選ぶ=Web系のキャリアに就くと思っている人もいるかもしれないが、Perlはもともと面倒なシステム管理タスクなどを簡単に包括的に行うためのツールとして作られているので、Web系に限らずその後もっと広いシステム領域に自分の仕事を広げていくつもりだったとしてPerlという言語は悪いチョイスではないと思います。

2. ただし書き

・・・とここまで書いておいてなんだけど、だからと言ってPerl勉強すればいいってもんじゃない。色々なただし書きがついてきます。

ここからはまとまりにくいのだけど、とりあえず羅列してみる:

  • 今回僕はPerlを便利なツールで、覚えておいて損はない、そして今ならある程度のPerl力があれば就職できる可能性が高いよ!って言いたいだけ。
  • Perlを覚える事にしたとしても、それだけでは何にもならない。優秀なプログラマーは第1言語以外のどの言語を与えても資料さえあればそれなりのものが作れる。重要なのは言語の仕様ではなくて、プログラムを書く時の考え方だから。だから他の言語も一緒に覚えればいいと思う。
  • Perlに関してはバッシングが結構ひどいけど、少なくとも「言語仕様」を叩く人の言うことは8割ほど引いて聞いておけ。他人のコードを読めないとのたまう人は自分が得意とする言語・環境以外のデバッグができないだけだし、まずいコードを書く人はどの言語で書かせてもまずいコードを書く。

3. ということで

今はPerlは戦略的に就活を行うなら、早い内から手に入れておいて役に立つスキルのひとつだと思う。ただしYMMV

4. ついでに

あくまで個人的な意見ですが、今から新たにPerlの何かを覚える目標としてはPlack/PSGIともっと進んだところでは非同期プログラミングはいい題材だと思います。技術的なレベルはちょっと高いけど、その辺りを目指すと外れはないかな〜。まぁこれは本当に個人的意見なので初心者には辛いかもしれません。

あとこれからPerlを覚えようって方には(もっと他にもあるだろうけど)とりあえずPerl関連書籍Perl関連資料のページも作りましたよ。

あと、Perlメインでなくてもいいので、Perlで開発を受注できる!という会社の方は是非こちらに書き込んでください!数が揃えばJPAサイトのほうに移します。
    このエントリーをはてなブックマークに追加 mixiチェック

松濤であった爆発の件について、そういえばtwitter使ってたなーと思って探したら全然見あたらない。なにせ4年近く前のことなのでそもそもそこにたどり着くラインがないのだ。

なので、一個だけブクマされてたtweetから超ローテクな方法で残りのヤツを捜した。その方法とは・・・一個ずつIDを増やして、HTTP GETが通ったらOKというだけ。一旦書いてから走らせてそのまま放置して一晩おいておいたら大体とれてたくさい。

というわけで、松濤温泉施設爆発時の俺のtweet → ここ


use strict;
use LWP::UserAgent;

my $base = 110764722;
my $ua = LWP::UserAgent->new();
my $i = $base;
while(1) {
    my $res = $ua->head("http://twitter.com/lestrrat/statuses/$i");
    if ($res->is_success) {
        print "http://twitter.com/lestrrat/statuses/$i\n";
    }
    $i++;
}
やー、ローテクですね。あまりオススメしませんw
    このエントリーをはてなブックマークに追加 mixiチェック

Perlを使うことのできる中小企業(地方企業含む)って結構いると思うんだけど、そういうのをとりまとめたリストを作って公表するとか、もしくは弊社(endeworks)と取引のあるところと今後の仕事の際にそういう会社に仕事を流して関係を築いていくとか、そういうのって需要あるのかなぁ?

発注したい側、受注したい側、両方とも意見が聞けると嬉しい。

追記1: 見切り発車でこんなwikiページも作ってみました。よろしかったら書き込んでください!

追記2: リンク先間違ってました!直しました!
    このエントリーをはてなブックマークに追加 mixiチェック

「だからどうだ」ってことですけど、(perlだとreverseあるので本来なら1オペで終わっちゃうけど)とりあえずループを使わずに与えた配列を逆にするコードの自己最短コードはこうなりました:

sub r{@_?(pop,r(@_)):()};
もう少し読みやすく展開するとこんな感じですね。ただの再帰処理です:

sub myreverse {
   if (@_ > 0) {
      return (pop @_, myreverse(@_));
   } else {
      return ();
   }
}
popで配列の最後の要素を最初に回して、残りを再帰処理してるだけー
    このエントリーをはてなブックマークに追加 mixiチェック

  • 注1:まだ本番にはデプロイしてませんが、確認テストでは使いました(単位テストでは使わない。あくまで本番さながらの形で動いているのを確認したい時だけ)。
  • 注2:以下スクリプトは開発者の労力を減らすためのスクリプトで、万全なデプロイ方法だとか言うわけではありません。
  • 注3:正直シェルスクリプトは素人です。

  • 追記:envdirはどうか、と言われた件。最初それを思い出せなくてcat ENVなんてしてたんだけど、設定値をもらって後からフックしたいところがあるからenvdirではそれを実現できない・・・気がする。ので、今回は以下で。
  • hirose31 さんが美しい スクリプトを提供してくれたので、それをベースにしてgithubにあげておけました。最新版はここです

ここ最近のPlackだとかStarmanとかを使ったWebアプリケーションのバンドル・デプロイについてちょっと固まりつつあるので、書いてみる

まず アプリケーションと、その依存関係。デプロイ側のサーバーにはlocal::libと必要なModule::Install系のモジュール、それにModule::Install::Bundle::LocalLibがインストールされている前提です。アプリケーションの依存関係は全部Makefile.PLに書きます。

use inc::Module::Install;

name 'MyApp';

..... # 必要な事色々 ....

# Plack stuff
requires 'Plack' => '0.9910'; # or 1.00 when the time comes
requires 'Starman';
requires 'Server::Starter';
requires 'Net::Server::SS::PreFork';

bundle_local_lib;

WriteAll;

こんな風にしておく。で、デプロイする際には
make bundle_local_lib
する。するとextlibというディレクトリに依存関係が全部入ります。このextlibは一旦安定稼働するのを確認したら、依存関係のアップグレード時には一旦別のところに待避させるとかコピーするとかしてからアップグレードを行ってみるという事ができる。万が一動かない場合はすぐ元のextlibに戻せば良いってわけだ。

ってなわけで、Plackを含めた全ての依存関係をextlib以下にある。

で、これをdaemontoolsで動かすのでrunファイルが欲しい。作る。今までdaemontoolsで運用してて開発→デプロイで面倒くさいなーと思ってたのがこのrunファイルの細かい設定を変えていくことなんだけど、今回はこれを分離してみた:
#!/bin/sh

# ENVというファイルが このファイルと同じディレクトリか
# pwdにあれば、それを読み込んで、そこから環境変数を広う。
# 例えば後で出てくる PSGI_FILEの場所を明示的に指定したければ
# PSGI_FILE=/path/to/app.psgi とかENVファイルに書いておく。
if [ -f `dirname $0`/ENV ]; then
    ENV_FILE=`dirname $0`/ENV
    export `cat $ENV_FILE`
elif [ -f ENV ]; then
    export `cat ENV`
fi

if [ -z $APP_HOME ]; then
    APP_HOME=`pwd`;
fi
export APP_HOME
if [ -z $CATALYST_HOME ]; then
    CATALYST_HOME=$APP_HOME
    export CATALYST_HOME
fi

if [ -z $CATALYST_CONFIG ]; then
    if [ -f "catalyst.yaml" ]; then
        CATALYST_CONFIG=catalyst.yaml
        export CATALYST_CONFIG
    fi
fi

if [ ! -z $DEBUG ]; then
    DBIC_TRACE=2
    export DBIC_TRACE
fi

if [ -z $PLACK_SERVER ]; then
    PLACK_SERVER=Starman
fi

if [ -z $PSGI_FILE ]; then
    PSGI_FILE=app.psgi
fi

if [ -z $PORT ]; then
    PORT=5000
fi

if [ -z $USER ]; then
    USER=www
fi

if [ -z $PERL ]; then
    PERL=`which perl`
fi

EXTLIB=$APP_HOME/extlib

# start_serverを通して plackupを実行するのだが、こいつらはextlibの中に
# あるので、それを指定して実行する(local::lib設定もつけないと依存関係が
# みつからない状態になってしまう)
exec setuidgid $USER \
    $PERL -Mlocal::lib=$EXTLIB \
    $EXTLIB/bin/start_server --port $PORT -- \
    $PERL -Mlocal::lib=$EXTLIB \
    $EXTLIB/bin/plackup -s $PLACK_SERVER -a $PSGI_FILE -p $PORT 2>&1

こんな感じ。これでENVの中身を変えてsvc -tするとその設定が反映される、と。

自分の場合はPSGIファイルの中にももう少し仕掛けを入れていく必要があったので、ENVから可変な情報をもらっていくようにした:
use strict;
use lib "$ENV{CATALYST_HOME}/lib"; # パスを通す
use local::lib "$ENV{CATALYST_HOME}/extlib"; # ついでにlocal::libのパスも通す

use MyApp;
use Plack::Builder;

MyApp->setup_engine('PSGI');

builder {
    # リバースプロキシ使う場合はenableしちゃう
    if ($ENV{USE_PROXY}) {
        enable "Plack::Middleware::ReverseProxy";
    }
    return sub { MyApp->run(@_) };
};
これをレポジトリに入れておき、デプロイするときにはdaemontoolsあたりからsymlinkしておいて動かす。開発時にもrunファイルを実行すれば本番さながらの感じでサーバーが立ち上がる(ただし、実際にはテストは全然違う方法で動かしてる)

誰かの役に立つなら幸い。なんか突っ込みがあればお願いします。
    このエントリーをはてなブックマークに追加 mixiチェック

forでは$.はカウントされない

ちょっと違うので横から。

これはforの動作というより、式の評価コンテキストの問題。

forはその性質上、操作対象は配列になる:
for (<>) {
     ....
}

# 上記はこれと同等
my @lines = <>;
for(@lines) {
    ....
}
なので、<>も配列として評価されるべく*まず最初に*<>を最後まで読み切って、行区切りの配列を作ってからforに渡す。このときファイルハンドルを読み切っているので、当然 $.はファイル全体の行数になる。

これに対して、whiileは対象を毎ループ評価するので、1行ずつの読み込みになる。だから$.は行毎の値になる。B::Deparseを使うとちょっとわかるかも。
# こっちはちょっと正直わかりにくいとは思うけど・・・
daisuke@beefcake $ perl -MO=Deparse -e 'print $. . $_ for <>'
;
print $. . $_ foreach (<ARGV>);
-e syntax OK

# こちらでは $_ = という操作になっているので、1行毎読み込んでるのが
# はっきりわかる。
daisuke@beefcake $ perl -MO=Deparse -e 'print $. . $_ while <>'
print $. . $_ while defined($_ = <ARGV>);
-e syntax OK
というわけで、forが違うというよりはファイルハンドルをリストコンテキストで読み込んだ場合とスカラーコンテキストで読み込んだ場合の動作が違う、っていうのが正解。
    このエントリーをはてなブックマークに追加 mixiチェック

ちょっとずれてるので横からコメント

unshift、push で変更を加えた @INC(モジュール検索PATH)が使用されない
起こってる現象とこの認識はちょっと違う。

具体的に何が起こっているか説明する前に、Perlにはコンパイル(BEGIN) フェーズとランタイムフェーズという、2回コードが実行されるタイミングがある(まぁ厳密にはもう少し色々フックすることが可能だけど、とりあえず一般的にはその二つで大丈夫)。

これがどういうことかというと、順番にコードを書いているつもりでもコンパイルフェーズで評価される部分とランタイムフェーズで評価される部分があるということ。わかりやすい例としてはこんな感じか:

#!/usr/bin/perl
use strict;
print "Runtime!\n";

BEGIN {
    print "Compile time!\n";
}

BEGINで囲まれた部分はコンパイルフェーズで実行され、BEGINの前にあるprint文より前に実行されるはず。

で、一般的にモジュールを読み込む"use"宣言はどうかというと、これはコンパイルフェーズで実行される。"use"宣言というのは実は以下の構文と同等なのだ:
# use MyClass;
BEGIN {
    require MyClass;
    MyClass->import;
}

つまり、use宣言で扱うクラス名が発見されるためには、コンパイルフェーズ時に@INCが変更されてなくてはならない。mod_perlだろうとなんだろうとこれは一緒なので、mod_perlじゃなくても以下のコードではMyClassは見つからない:
unshift @INC, "/path/to/MyClass";
use MyClass;
つまり、"/path/to/MyClass"をuse宣言に認識させるためには以下のようにする必要がある:
BEGIN {
    unshift @INC, "/path/to/MyClass";
}
use MyClass;
これなら、どちらもコンパイルフェーズで動き、あとは読み込まれた順番に処理されるから問題無し!

まぁでもmod_perlを使うのなら、なにか制限がない限りstartup.plで@INCを普通にunshift/pushで変更しておくのが一番いいと思う。
    このエントリーをはてなブックマークに追加 mixiチェック

検索エンジンの皆様こんにちは。2010年以降のPerlウェブサーバーといえばPlack/PSGIですね。そんなSEOな記事です。

私がPerlでWebアプリ的な物を初めて書いたのは1999~2000年にかけての事なのでそれ以来ほぼ10年たっているわけです。その間に色々さわりました。ウェブサーバーとアプリをつなぐアダプターのレイヤーとしてはCGI.pm, mod_perl, FastCGIなどを使ってきました。フレームワークもMason, Sledge, Catalyst, AxKitなんかをさわってきました。

どれもこれもいいところもあり悪いところもあり、それぞれコメントしたい部分はあるのですが、とにかくデプロイ方式が全然違うのでどうにもできん、という問題がずっとありました。

しかし PSGIというPerlウェブアプリケーション用の規格ができたことにより、これは全く変わってきました。PSGI規格に準じていれば、フレームワークがなんだろうとサーバーがなんだろうと同じ方式でがっちゃんこできるのです。これはいままで「Perlをレンタルサーバーでデプロイできねぇよ」とか言ってた層には素晴らしい事で、ホスティングプロバイダのほうがそのPSGI形式さえサポートしてくれれば、がんがんデプロイできちゃったりするんですね。

これは是非みなさん、まわりのPerlの事をちょっと遠くから見ていた人たちにも是非教えてあげて下さいね!

日本語での記事が足りない気がしたので書いてみました。
    このエントリーをはてなブックマークに追加 mixiチェック

dve_deprecated.png

I'll support it for a while should there be any problems , but in general, please consider using Data::Recursive::Encode instead.

Data::Visitor::Encodeの開発を停止します。もうしばらくの間は問題等あればサポートしますが、基本的にはData::Recursive::Encodeを使って下さい。
    このエントリーをはてなブックマークに追加 mixiチェック

企画が出ただけの段階なので、まだなんとも言えないのですが、2010年5月〜7月くらいに東京以外の某場所でYet another Perl UNconference (YPUN)を開催しようかという話が出ました。

アンカンファレンスに関してはこちらを参照

まだこれから諸々調整があるのでぼかした言い方ばかりで申し訳ないのですが、一応考えているのはこんな感じ:

  • 某地方都市で泊まりがけ
  • キーノートだけこちらで設定
  • 地元企業もからめてBOF
  • あとはアンカンファレンスで話したい内容を思い思いに
  • Perlとはあるけど、ゆる〜〜〜〜〜い縛りで
  • なるたけうまく方々と調整して参加者は基本的に交通費だけで済ませることができるようにしたい!
  • 今候補に挙がっている場所は某中部地方エリア
  • うまくいくようなら定期的に地方都市で巡回開催したい!
ちなみに直接の発案者は僕じゃないので、この企画が本当に通るかどうかは Emersonさんに頼るところが大きいです!メアドをさらすわけにはいかないので・・・twitter で@okaihatuしちゃえ!w
    このエントリーをはてなブックマークに追加 mixiチェック

このページのトップヘ