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.

2011年04月

最近PSGI/Perlをサポートし始めたdotCloudのinvite codeをもらったのでとりあえずHello World的なアプリを作った。

作り方だが、まずdotcloud用のツール類をインストールする必要がある。自分のマシンでpythonを動かした事がなかったのでそこから。まず自分のpythonは homebrew経由で入っているヤツで、全てユーザー権限で入っているのでsudoとか使ってないのに注意。

easy_install dotcloud
docloudではまず"deploy"というものを作る。deployは複数の"service"の集合体。"service"はそれぞれが一個のアプリなり、データベースなりを指す(はず)

なのでまず適当に"lestrrat"というdeployを作り

dotcloud create lestrrat
次に"lestrrat.www"というserviceを作る

dotcloud deploy --type perl lestrrat.www

この段階ではまだインフラがセットアップされているだけでアプリ自体は空。アプリ自体はどこに作ってもよくて、次のステップでそのディレクトリを指定すればOK。ここでは仮に~/git/lestrrat.wwwにあるとする

次にアプリそのものをリモートのserviceにpushしないといけない。

デフォルトの挙動では、以下のようにすると特定のディレクトリの中身を*全て*pushする。

dotcloud push lestrrat.www ~/git/lestrrat.www
ただ、ちゃんとバージョンコントロールをしたい場合は現段階ではhgとgitがサポートされていて、この場合は若干挙動が違う。

もし指定されたディレクトリに.gitディレクトリがあれば、リモートにgit pushしたのと同じような動作になる。つまり、git commitしてないファイルはpushされない。自分はとりあえず作業量のディレクトリを作り、git initした。

つぎ。リモート側で動くアプリは当然PerlにしたいのでPSGIファイルが必要なのだが、dotcloudではserviceディレクトリのルートにあるapp.psgiというファイルがデプロイされる。

追記5/1: 今回は生PSGIファイルを使うけれども、当然CatalystDancerMojoliciousをデプロイすることが可能だ。この記事では動くまでの理屈を追いたいので敢えてフレームワーク等は使ってないけれども、普通は何らかの形でそういうフレームワークを使う事になるだろう。それぞれの使い方はリンクを参照のこと。

dotcloudのチュートリアルではこのファイルはbinに実体を置いて、ルートにはsymlinkをつける、というような形になっていたが、なんせHello Worldで面倒くさいのでそのままぼん、とルートに置いた。

内容は以下のような感じ。

use strict;
return sub {
    my $env = shift;
    return [
        200,
        [ 'Content-Type' => 'text/html' ],
        [
            "<html><head><title>Hello</title></head>",
            "<body><h1>Hello, Stranger</h1><p>Here's a dump of what I know about you</p>",
            (map { "<tr><td>$_</td><td>$env->{$_}</td></tr>\n" }
                grep { /^HTTP_/ }
                keys %$env),
            "</table></body></html>"
        ],
    ]
};

これを以下のコマンドでリモート側に送ると、向こうで色々魔法が起こって、サービスが http://www.lestrrat.dotcloud.com/ であがっている・・・という感じ。

 dotcloud push lestrrat.www ~/git/lestrrat.www

ちなみに最後のコマンドはもう書くのが嫌になったので、Makefile.PLを作って以下のような記述をしておいた。これでmake dotcloudでpushされる。(注意!Module::Installを使う場合はinc/以下もpushしないといけないので、git commitしないといけないようです!)

use inc::Module::Install;

name 'lestrrat-DotCloud-Hello-World';
version '0.01';

postamble(<<EOM);
dotcloud:
     dotcloud push lestrrat.www \$(PWD)
EOM

WriteAll;

あと依存関係の類もMakefile.PLで解決してくれるとのこと。やったね!

ってことで、近々dotCloudでアプリをつくるですよ
    このエントリーをはてなブックマークに追加 mixiチェック

LinuxやMac OS Xを使っていれば、大抵の場合/usr/bin/perl などの位置にPerlが入っていますが・・・これらを使うのはやめたほうがいい、というのが段々定説になりつつあります。

厳密に言うと、別に簡単なスクリプトを書くのにシステム標準Perlを使うのは問題ないのだけれども、CPANからモジュールをインストールするつもりならシステム標準Perlを使わないほうがいいでしょう、という事ですね。

自分としてはシステムPerlを使わない理由はふたつある。

ひとつはシステムPerlはそれに依存するものがOS・システム本体にあるため、それに変更を加えると何かが壊れることがあること。例えばついうっかりモジュールのバージョンをあげてAPIが変わってしまったためになにかが壊れるとか、Perl-5.14.0 を使いたい!と思った時にシステムPerlが5.10.0でアップグレードすると怖いとか。

もう一つはこういうわけのわからない理由で急に動かなくなったりしないから。自分があずかり知らないところで起こった事で自分のPerlが動かなくなるとか意味がわからん。

これからPerlを始めようという人は迷わず perlbrew を使うといいと思う。perlbrewなら複数のPerlを管理できるし、ユーザーの権限でperl本体やモジュールが入るのでsudoとかルート権限とか悩まないで済むし、自分だけが使うので知らないところで他の何かを壊す心配がぐっと減る。

ちなみに僕のマシンには今これだけのPerlが入ってます!下の二つは、5.8.9が昔いれたhomebrew のperl、/usr/bin/perlはシステム標準 Perlです。設定に失敗したらインストールをし直せばいいだけだし、気楽にいろんなperlが入りますね!これからは是非自分のPerlで作業してみてください!

daisuke@beefcake ~$ perlbrew list
  perl-5.12.2
  perl-5.12.2-threaded
  perl-5.12.3
  perl-5.12.3-threaded
* perl-5.14.0-RC1
  perl-5.8.9
  /usr/local/bin/perl (5.8.9)
  /usr/bin/perl (5.10.0)

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

@tomitaさんが書いた「CPANモジュールガイド」の刊行記念ということで池袋のジュンク堂本店で話して・・・もとい、コードを書いてきました。普段は滅多にこういう場に現れない「初めてのPerl」や「プログラミングPerl」の翻訳者である近藤嘉雪氏がもう一人のゲスト。司会がもはや技術界のタモリと化しつつある@yusukebe。あと@941さんがスタッフとして手伝いに来てくれました

近藤さんを見られるというだけでも実はすごいイベントだった気がする。ちなみに近藤さんは出番直前まで頑張ってスライドを書いていて、そのおかげで話にクロージャが含まれたそうです!

こちらは@tomitaさんが書いた店頭POP。「Placクマ」の二重のパクリがひどいですねwww !


イベントの内容自体は・・・なんだかリハーサルというか、ちゃんとした打ち合わせもしてなかったのに、すごく内容が良い感じになった気がしますね。Perlの基本を@tomitaさんと近藤さんが丁寧に説明してくれて、最後に僕がわーーーっとCPANモジュールを使ってコードを書く過程をなぞる、という感じ。

自分の発表はCPAN 30分クッキングということでCPANから色々ダウンロードしてきてFacebook::Graphとか使ったらこうなるよー的なコードをざくざく書きました。

最終的に書いたコードは、@sugyanさんのブログのパクリと、自分の友達のタイムラインからロケタッチのリンクを抜き出してきてHTMLを作る、というようなもの。本番では実はトラブルがあって最後のロケタッチページを作成するためのHTTPリクエストがうまく動かなかったので一瞬焦ったが、「CPAN 30分クッキング」ということで「すでにこちらに出来たものがございます」というものを用意しておいたので助かった。一応その程度のネタは仕込んでおいてよかった・・・

というわけでなかなか楽しかった!みんな、もっと僕らの本を買ってくれると次が出せるようになるからよろしくお願いします!w


さて、僕の発表ですが、全然中身はないですが、スライドは以下のような感じ:


あと一応こちらがコード。最初にconfig.plというファイルの中に自分のFacebookアプリ用のapp_idとsecretを入れておく

return {
    app_id => "XXX your app ID",
    secret  => "XXX your app secret"
};

まずはsugyanさんのパクリのヤツ。アクセストークンをコピペするのが面倒くさいのでコンフィグファイルにダンプするようにしてある:

use strict;
use Data::Dumper;
use Facebook::Graph;
use Plack::Request;

my $config = require "config.pl";
my $fb = Facebook::Graph->new(
    app_id => $config->{app_id},
    secret => $config->{secret},
    postback => "http://localhost:5000/"
);

return sub {
    my $env = shift;
    my $req = Plack::Request->new($env);

    if ( my $code = $req->param('code') ) {
      warn "requesting access_token";
        $fb->request_access_token( $code );
        my $dump = Dumper({
            %$config,
            access_token => $fb->access_token
        });
        $dump =~ s/\$VAR = //;

        open my $fh, '>', "config.pl" or
            die;
        print $fh $dump;
        close $fh;
        return [ 200, [], [ $fb->access_token ] ];
    }
      warn "redirect";

    return [
        302,
        [
            Location => $fb->authorize
                ->extend_permissions( "publish_stream" )

                ->uri_as_string
        ],
        []
    ];
}

で、こっちがFacebookにアクセスしてロケタッチのデータだけ抜き出してくるヤツ。普通にFacebook::GraphのAPI使ってたらおせーな、と思ったのでFurl+Coroしてみた。よくよく考えてみると CoroとCoro::LWPしとけばFurl使わなくても多重化できるから速くなる気がするが、まぁ後悔はしてない

use strict;
use Text::Xslate;
use JSON;
use Coro;
use Coro::Select;
use Furl::HTTP;
use Facebook::Graph;
use Data::Dumper::Concise;

my $config = require "config.pl";
my $fb = Facebook::Graph->new(
    app_id => $config->{app_id},
    secret => $config->{secret},
    access_token => $config->{access_token},
);
my $data = $fb->query->find("me/friends")->request->as_hashref;

my $furl = Furl::HTTP->new;
my @coros;
foreach my $friend ( @{ $data->{data} } ) {
    my $q = $fb->query->find( "$friend->{id}/feed" );
    push @coros, async {
        my (undef, $code, undef, undef, $body ) = $furl->get( $q->uri_as_string 
);
        return unless $code eq 200;
        return decode_json $body;
    } $q->uri_as_string;
}

my @spots;
foreach my $coro (@coros) {
    my $feed = $coro->join;
    next unless $feed;
    foreach my $entry ( @{ $feed->{data} } ) {
        if ( $entry->{caption} eq 'tou.ch' ) {
            push @spots, $entry->{link};
        }
    }

}

my $xslate = Text::Xslate->new(
    path => [ "." ],
    syntax => 'TTerse',
);

print $xslate->render_string( <<'EOM', { spots => \@spots } );
<script type="text/javascript" src="jquery-1.5.2.min.js">
<script type="text/javascript">
var urls = [ [% FOREACH spot IN spots %]"[% spot %]"[% IF ! loop.last %],[% END %][% END %] ];

$(document).ready( function() {
    var delay = 200;
    var f = function() {
        url = urls.pop();
        url = url.replace( /\/$/, "" );
        url = url.replace(/\/spot/, "/widget/spot");
        var iframe = $('<iframe frameborder="0" scrolling="no" allowtransparency="ture" height="321" width="350" src="' + url + '?i=0&m=1&t=blue&width=350"></iframe>');
        $("#container").append( iframe );
        setInterval(f, delay);
    };
    f();
} );

</script>
<div id="container"></div>
EOM
    このエントリーをはてなブックマークに追加 mixiチェック

コンフィは主に鴨のコンフィが大好きで、時折入った店で見つけると大抵オーダーしてしまう。しかし使わなければいけない油の量や、仕込みが多少時間かかるので面倒で手を出さなかったが、震災直後に日本経済を活性化させるという名目の元にkazuhoさんとつくしのこに行った時に「簡単ですよ!」って超オススメされたので近いうちにやろうと思っていた。

さて、まぁそんなわけで連休の今日、ついに手を出してしまったわけです。まずは朝ご飯のパンを近所のパン屋で買って、最寄りのコーヒー屋で飲み物を買いそのパンとコーヒーで朝食をすます。その足でスーパーで鶏モモ肉と砂肝を結構大量に購入。万が一作りきれなかったとしても鶏肉だったら使えるしね。あとは生のローズマリーとニンニクを購入。

その量の肉をオーブンに突っ込むとなるとうちにすでにある耐熱皿のサイズが微妙なのでついでに帰り道で若干深めの耐熱皿を購入。

家に帰ってまず下処理を開始。軽くあらって水気を切ってからモモ肉から余分な皮や油を切り、塩をしてジップロック袋に。砂肝は食べやすいサイズに切って、若干切れ目を。本当は筋を全部切ってもいいんだけど面倒臭いのでそれくらいにしておいた。それも袋にいれて、両方とも塩がまわるようにもみもみ。あとは調理を始めるまで放っておく。

肉は半日そんな状態でおいておいて、調理時間は1時間半~2時間なので晩ご飯から逆算してそれくらいの時間に調理開始。水気を拭いて耐熱皿に並べて、みじん切りのニンニクとローズマリーを入れて、そこにサラダオイルとオリーブオイルをどぼどぼ、ひたひたになるくらいに。あとは100度ないし120度くらいの設定にしてあるオーブンにそれを突っ込むだけ。

さすがに初めてのコンフィだったので時折オーブンを開けたりしながら様子を見たが、見る度にゆっくり火が通っていくのがわかってワクワク。でもこの調子なら本当に放っておくだけでよさそうですね。

時間がきたら一応火が通ってるかだけ確認して、油からモモ肉を出してやり軽く油を切る。それに強火でさくっと焦げ目をつけてできあがり!付け合わせは面倒だったので冷凍野菜を軽く茹でたものを。さすがに油で煮てるので付け合わせはさっぱり系が個人的にはオススメ。できあがった肉はしっとり軟らかく、ハーブの香りもキチンとして、うまうま。これはいい!

今日は元々出来た物をすぐ食べるつもりで調理したので2時間たった時すぐ食べてしまったけど本来はもう一日くらいおいた方が味がしみてよいそうだ。

夕飯分だけでは全部の肉が消費できなかったので、今これを下記ながらもう一回オーブンに第二弾を突っ込んで焼いている。こちらはまた明日以降食べる。むふふ。

もう少し練習したら鴨のコンフィをつくるのだー。

ちなみに調理の行程とかはデイリーポータルさんにとてもいい記事がありますね。下処理だけすれば簡単な料理でした!今後は定期的にやるぞー
    このエントリーをはてなブックマークに追加 mixiチェック

なんかふと気づいたら最近以前書いたPerlでシグナル処理の記事にブクマがついていたので続き的な感じで書いてみた。

例えば 以下のように、ワーカーとかでずーーーーっとDBにクエリを投げてその結果を使って処理をする、というような処理を書くとする

     while ( $loop ) {
         my $sth = $dbh->prepare( .... );
         $sth->execute();
         while ( $sth->fetchrow_arrayref ) {
              ....
         }
     }

以前書いた%SIGを用いたPerlの普通のシグナル処理では、もしexecute()でブロックしていた場合など(例:Q4Mでqueue_waitしてる)ではいくらSIGINTとかを送ってもブロックしたまんまになる。理由はPerlの素のシグナル処理は*Perlの*1オペと1オペの間に実行されるから。データベースに対する処理はCレベルでブロックしていて、実はこれはほとんどの場合Perlの1オペがブロックしてる間に終わらない

そういう場合は%SIGでシグナル処理をするのではなくて、POSIX::SigActionとかを使う。POSIXレイヤーでシグナルハンドラを指定できるので、Cレイヤでのブロック状態中でもシグナルハンドラを呼び出せる。Perlの世界から見ると、Perlのオペ完了を待たずにすぐに実行されるのでこれらをリアルタイムシグナルと呼ぶ。基本の使い方はperldoc POSIXした時にでてくる。

で、シグナルを受け取った時に現在実行中のステートメントハンドラをキャンセルするには$sth->>cancelを呼べばいいし、ついでにDBも接続を落としちゃうなら$dbh->disconnectとかしちゃえばいい

    use POSIX qw(:signal_h); # import SIGINT, SIGTERM, and other signal related stuff

    my $sth; # declare now to make it accessible
    my $sigset = POSIX::SigSet->new( SIGINT ); # specify which sig we're handling
    my $cancel = POSIX::SigAction->new(sub { # the handler
        if ( $loop ) {
            eval { $sth->cancel };
            eval { $dbh->disconnect };
            $loop = 0;
        }
    }, $sigset, &POSIX::SA_NOCLDSTOP);
    POSIX::sigaction( SIGINT, $cancel ); # register them handler

    while( $loop ) {
        $sth = $dbh->prepare( ... );
        $sth->execute();
        while ( $sth->fetchrow_arrayref ) {
             ....
        }
     }

これでSIGINTでちゃんとキャンセルされる。ただ、当然ながらキャンセルされた結果undefになる変数とかがあるなら、それは while の中で参照しないように自分で気をつけて処理をするように。

あと、sigaction() でシグナル設定するの面倒くさいよ!って人は%SIGRTっていう、リアルタイムシグナル用の%SIGハッシュがあるらしい。自分は間違えそうなので使ってないけど。use POSIX; すると自動的に現スコープから参照できるようになる。

そうそう、激しくオフトピだけど、use POSIX; は、実に数百個(うろ覚え)もの関数や変数を現パッケージにインポートするので、効率を重視したいなら注意。必要なものだけ明示的にインポートするか、常にPOSIX::hogeのようにして参照するほうがよいだしょう。
    このエントリーをはてなブックマークに追加 mixiチェック

追記2:参考まで【その1】【その2】。そして僕は最初に書いた時も、sysreadの指摘を受けたときも正直な感想としては「そこまで考えて使ってません!」みんなよう気づくわ。すごいっす。

追記:間違えてた。ほんとだー。そう言われれば当たり前ですねすみません。sysreadのほうが速いのは当然です!

use strict;
use Benchmark qw(cmpthese);

cmpthese -1, {
    sysread => sub {
        my $buf;
        open my $fh, '<', __FILE__; 
        sysread $fh, $buf, -s __FILE__;
    },
    slurp_local => sub {
        local $/;
        open my $fh, '<', __FILE__;
        my $buf = <$fh>;
    }
};

なんかtwitter見てたらこういうのを貼ってる人がいたので、一応書いておく。

Perlでファイルを一気に読み込むのは local $/; <$fh> が一番速い。

     open my $fh, '<', "/path/to/file.txt"
         or die "failed to open file: $!";
     my $content = do { local $/; <$fh> };

いずれにせよ大きいファイルを処理する場合はこういう風に一気に読み込むのは効率悪い。それを分かった上で、それでも1行ずつ改行コードが取り除かれた状態で配列に読み込みたいならこれをsplitするのが一番速い

     open my $fh, '<', "/path/to/file.txt"
         or die "failed to open file: $!";
     my @lines = split /\n/, do { local $/; <$fh> };

単純に一行ずつ処理する、という話だったら一括読み込みとかは忘れて、一行ずつ処理がベター。

    open my $fh, '<', "/path/to/file.txt"
         or die "failed to open file: $!";
    while (my $ln = <$fh>) {
         ....
    }
    このエントリーをはてなブックマークに追加 mixiチェック

ちょっと前に読み終わってた。作中の心情描写にバイアスはかかってるが、良い感じの話だった。しかしまぁ・・・終わり方はこういう終わり方しかできんのかね。

この前読んだ本達もそうだけど、映画は観てない。

次は何をよむかなぁ。文庫本で400ページくらいで比較的さくっと読めて、セリフばっかりじゃない本。なんかないですかねぇ。
    このエントリーをはてなブックマークに追加 mixiチェック

久しぶりに週末に実家に帰る予定もなくそれ以外の用事もなかった上、天気がいいと。そんなわけで突然夢の島に行こうと思い、見たところ熱帯植物園なるものがあるらしいので行ってきた。



ブラジルに住んでた頃は庭にパパイヤの木がある家に住んだ事もあるし、アロエ、ジャボチカーバ、マラクジャは比較的あちこちにあったなー

お弁当を食べた後、まだ12時前だったし折角りんかい線もあるのでこういう機会でも無い限り絶対行かないだろうと思って若人やおされな人が集まるお台場なる場所に行ってみようと思い、りんかい線で移動。

相方が特に断らないので流れで観覧車に乗せる。もう怖がって全く外を見なくて、ずっと藤村Dの真似して動画回してしまった・・


あとはヴィーナスフォートを見たり、海浜公園をちらりと散歩したり、フジテレビをさらっと見たり。あまたつ〜!

まぁお台場はお台場でした。おもしろい人いっぱいいたけど、俺多分もういかねぇだろうなー。帰宅して風呂って飯して相方が昨日作ったチーズケーキ食べたりして今にいたる。
    このエントリーをはてなブックマークに追加 mixiチェック

WebAppで DBIをなんらかの方法でDBに接続して、で、リクエストが終わったら接続を解除して・・・とかしたいとするじゃないですか。具体的な実装はScope::Containerでもなんでもいいんですけど。

それでなんかしらんけど、アクセスするたびに三つずつDB接続が残る、という現象に遭遇したわけですよ。最初は普通に「あれ、Scope::Containerの使い方間違ってたか」とか思ってたんですが、何をしてもダメだし、Scope::Containerに手を加えて現在の保持してる変数を抜き出しても何もない。DBI::db へのリファレンスがないのに接続が切れないなんて・・・と途方に暮れることと数時間。

・・・やっちまったよ。ワーカーも同じ設定使うからーってのと、ワーカーはフォークするからーとか考えて適当に入れた次の設定がまずかった

     InactiveDestroy => 1

これ、つまりは$dbhをundefしようがなんだろうが、DBサーバーとの接続が切れないってことなんだね。普通は親プロセスがconnectして、forkした子プロセスがexitしちゃった時についでに$dbhが保持してる接続を解放しないように**子プロセス**で設定するものなんだけど、親でこれを設定してしまうと、永遠にDBへの接続が切れません・・・

なんてこたぁない、俺のやりたかったのは、こちらでした

    AutoInactiveDestory => 1
こっちは、「もし子プロセスを作るなら、自動的にInactiveDestroyを有効にした状態にしろ」っていうことなので、親プロセスは通常通りにundef $dbhで接続が切れる。

あー、あほくさかった。おれの午後を返せ。よい子のみんなは真似しちゃダメだぞ!
    このエントリーをはてなブックマークに追加 mixiチェック

「ゴールデンスランバー」と「幻夜」を読んだので読んだことだけメモ。

どちらかというと「幻夜」のほうが好きかな。しかし両方ともエンディングはちょっと腑に落ちない。最近の作品はわかりやすいカタルシスを求めてはいけないのかな・・・

それとなんで最近の文庫本はこんなに高いの!もとからこうだったっけ?700円くらいなイメージだったんだけどな・・・昭和か、それは。
    このエントリーをはてなブックマークに追加 mixiチェック


毎年恒例の行事になりつつある、桜の季節の呑川散策。ここは自粛モードじゃなくても桜の周りに陣取ってる花見客もいないし、桜を愛でるにはちょうどいい。今年はNEX-5という強い味方もいるし、ってことで朝イチで投票に行ってから移動。

行程としては桜新町から自由が丘まで。呑川緑道を歩き、八雲あたりでぐっと右折して自由が丘に折れていった感じ。

呑川の桜は正直今日もまだ満開!結構な数の散歩の人も。我々は時折写真を撮りつつてくてくと、1時間半ほど歩いた。

自由が丘について、スタバでちょいと休憩。ブックオフで本を物色してから渋谷へ行き、タイ料理を食べてから帰宅。

写真について。このエントリの一番上にあるパノラマ写真NEX-5のスライドパノラマという機能で撮った。今回初めて使ったのだけど、桜並木みたいな広い範囲を撮ると結構良い感じになるので楽しい。

ついでにXperiaとNEX-5の画質を比べてみた

NEX-5Xperia arc

Xperiaの方が若干暗い感じかなぁ。当然露出や絞りの調整ができる・できないはあるけど、まぁやっぱり携帯ということを考えると充分な気もする
でも本当、NEX-5はおすすめ!手軽な一眼レフを考えている方は1回試してみるといいんじゃないかなー

ちなみにもっと良い写真もあったんだが、相方が映ってるので検閲が入りましたw
    このエントリーをはてなブックマークに追加 mixiチェック

このページのトップヘ