空前の use Perl; ブーム
今 Perler の間では、use Perl; に英語で Perl ネタを書くのがアツイ、というわけで、自分もそのブームに便乗することにしました。まだ何も書いてませんが。
今後 Perl ネタはそっちの方に書くことにします。
あと、Yappo さんが use Perl; 一覧を XOXO で提供 してくれてますので、Perler な人は Plagger::Plugin::Subscription::XOXO で購読しない手はないでしょう。
Text::Trac のバグフィックス・機能追加とテスト駆動開発
rt.cpan.org でバグレポートと機能追加要望があがっていたので、久々に Text::Trac に手を入れました。
バグフィックスしたものは 0.05 としてアップしてあります。また、新機能として Trac Links と Wiki Macros をサポートしたものは、svn リポジトリに置いてあります。リクエストしてくれた方の確認後、問題なければ CPAN にアップ予定です。
今回のこのバグフィックスと機能追加で、TDD のありがたさを改めて実感しました。
バグについては一度修正して、報告者に確認をお願いしたのですが、まだバグが残っている状態でした。すると今度は報告者の方が、テストを書いて送ってくれたのですが、これが大いに役に立ちました。テストがあると、どこにどういったバグがあるのか、make test (あるいは prove コマンド)一発でわかるので、言葉で説明してもらうよりも明確ですし、バグ確認後、fail したテスト(と他のテスト)全てが通るようにプログラムに修正を施していけばいいわけで、やることが明確になって作業がスムーズにできました。
自分も今後バグレポートする際には、テストとセットでレポートするようにします。
新機能の追加についても、ひとつの機能毎にテストを書く、実装する、テスト動かして確認、修正する、というサイクルで作業していたのですが、コマンド一発でテストができると、全体の流れを途切れさせることなく、集中力を保ったまま作業ができていいですね。
これを機に Text::Trac のテストを Test::More から Test::Base へ移行したのですが、Test::Base で DRY にテストが書けると、更に全体の流れがよくなり、非常に気持ちよく作業ができます。Test::Base 最高。
Test::Base をご存知ない方は、Shibuya.pm テクニカルトーク #7 の 宮川さんの発表資料(PDF) を是非ご覧下さい。
HTML::Widget::Kwalify #2
先日のエントリで、「HTML::Widget が文字化けする」とか書いたのですが、HTML::Element の _xml_escape メソッドの問題 でした。
チケットは切られているので、とりあえず修正されるのを待つしかないのですが、2ヶ月以上放置されていて、早い対応は期待できなさそうなので、HTML::Widget::Kwalify に以下のコードを入れて強引に対処してます。
{
no warnings 'redefine';
*HTML::Element::_xml_escape = sub {
foreach my $x (@_) {
$x =~ s!([<&>])!'&#'.(ord($1)).';'!seg;
}
return;
};
}
あと、テスト追加したり、色々修正。ちょっとずつですが、形になってきてます。
HTML::Widget::Kwalify #1
HTML::Widget::Kwalify を修正しました。動作サンプルはこちら。
サンプルを触ってもらうと分かると思いますが、ポストしたデータを YAML 形式でダンプできます。また、フォームバリデーションにも対応してます。例えば、user_agent-timeout は Kwalify スキーマでは「type: int」と設定されているのですが、それに合わせてバリデーションルールも設定してあり、数字以外の文字列を入力すると「Invalid Input」と表示されます。
サンプルソースのメイン部分は、
sub top {
my $self = shift;
my $q = $self->query;
my $w = HTML::Widget::Kwalify->new('schema.yaml');
my $result = $q->param ? $w->process($q) : $w->process;
if ( $result->have_errors or !$q->param ) {
return $self->tt_process( 'index.html', { widget => $result } );
}
else {
$self->header_props( -type => 'text/plain' );
return $w->dump;
}
}
といった感じなのですが、たったこれだけでバリデーション、フィルイン対応のフォームを Kwalify スキーマから自動生成し、POST データを YAML にダンプ、ってなことができます。超ベンリ。
YAML はネストされたデータ構造なのに対し、HTML フォームは平坦な構造なので、この部分をどう処理するかが実装にあたって一番面倒そうだな、と思っていたのですが、宮川さんから Catalyst::Plugin::Params::Nested というモジュールを教えてもらい、これのベースクラスである CGI::Expand を使うことによって、簡単に実装できてしまいました。CGI::Expand++ 。
これで最低限やりたいことはできるようになりましたが、Kwalify スキーマのパースのしかたが適当なので、テストを書いて色んなパターンで試して調整する必要があったり、ファイルにダンプできるようにしたりとか、完成まではまだまだかかりそうです。
また、id:charsbar 氏 がおっしゃっている通り、HTML::Widget 自体が日本語が化けたりとか微妙な感じなので、こちらも手を入れないといけないですね。
Shibuya.pm テクニカルトーク #7
しゃべってきました。資料は後日 Shibuya.pm のサイトにアップされると思いますが、とりあえずここにも置いておきます。
CVS のことを CSV と書き間違えてて、後から指摘されて知ったのですが、実はしゃべってる最中に irc#shibuya.pm@freenode でいじられていたことを、帰宅してから知りました。アップした資料では修正してますが、ただ直すのもなんなので、ちょっと改変してあります。
プレゼン中も IRC を見ることができて、ダイレクトにつっこまれながらプレゼン、ってのもおもしろいかも、とか思いました。2 画面で一方は IRC のログ流しておくとか。
また、プレゼン資料中に出てきた Plagger プラグインは、話したとおり某 CTO が某ブクマのコメントで名前だけ出していたもので、実在はしません。期待された方、ごめんなさい。
イベントの内容は色々な人がレビュー書くでしょうからそれに任せるとして、スピーカやってよかったな、と思ったのは、ブログのコメントや IRC なんかでやりとりしただけで、お会いしたことがなかった方に声をかけて頂けたことですね。スピーカやらないと、その場にいても気づいてもらえませんから。
その後の飲み会でも、他社の開発や運用方法、内情などが聞けて楽しかったです。といっても、人数多かったので全然話せなかった方もいたり、家が遠いので一番最初に切り上げざるを得なかったのが残念でしたが、それはまた次の機会の楽しみに、ということで。
動画はこちらで後日アップされるようです。ちょっと緊張してて、記憶が飛んでるところもあるので、あとで自分のしゃべりを確認してみようと思います。
HTML::Widget::Kwalify #0
HTML::Widget::Kwalify というものをつくってます。まだプロトタイプにもなってない感じだけど。
これで Kwalify スキーマから HTML::Widget オブジェクトを自動生成して、Plagger のウェブインターフェースを簡単につくっちゃおう、という目論見です。
use HTML::Widget::Kwalify; my $w = HTML::Widget::Kwalify->create_from( file => 'schema.yaml' ); print $w->process;
みたいな感じで、schema.yaml から HTML フォームを一発で生成できます。
CGI::Application ベースでサンプルをつくると、こんな感じになります。
まずはディスパッチする index.cgi 。
#!/usr/local/bin/perl use strict; use warnings; use lib './lib'; use WidgetKwalify; my $w = WidgetKwalify->new; $w->run;
本体の lib/WidgetKwalify.pm 。
package WidgetKwalify;
use strict;
use warnings;
use base qw( CGI::Application );
use HTML::Widget::Kwalify;
use CGI::Application::Plugin::TT;
our $TEMPLATE_OPTIONS = {
INCLUDE_PATH => '/path/to/template',
};
sub setup {
my $self = shift;
$self->start_mode('top');
$self->run_modes(
top => 'top',
);
$self->tt_config( TEMPLATE_OPTIONS => $TEMPLATE_OPTIONS );
}
sub top {
my $self = shift;
my $q = $self->query;
my $w = HTML::Widget::Kwalify->create_from( file => 'schema.yaml' );
return $self->tt_process(
'index.html',
{ widget => $q ? $w->process($q) : $w->process }
);
}
1;
HTML テンプレート template/index.html 。
<table>
[% FOREACH element = widget.elements %]
<tr>
<td>[% element.label.content.0 %]:</td>
<td>[% element.element.as_XML %]</td>
</tr>
[% END %]
</table>
Plagger の example にある schema.yaml の global セクションを使ってこのサンプルを動かすと、こんな感じになります。まだ type:seq の処理をちゃんとしてないので、plugin_path が変ですが、他は良い感じ。log-level もちゃんと select になってるし。
これで、Plagger ホスティングウェブアプリつくれば、bloglines2gmail とか youtube2podcast とか、目的別にスキーマファイルつくるだけで、設定用フォームが自動で生成できるし、プラグイン毎にスキーマファイル用意しておいて、利用したいプラグインを選択すると、そのプラグイン用の設定フォームが自動で生成できる、といったことが可能になりますね。
あと、
$widget->process($query)->save_to( file => 'config.yaml' );
な感じで POST したフォームの内容を YAML にしてファイルに保存、とかできるようにする予定です。(他にも type: seq の処理とか、フォームバリデーション対応とか、やること山積みですが。)
Net::Amazon::ECS
Plagger で Amazon Web Service をつかって、発売日を Publish::iCal して Google Calendar で表示したり、今日・明日発売する商品を Publish::Gmail してるのですが、なんか最近 Google Calendar に表示される商品数が少ないな、と思ったら、AWS3.0 で ReleaseDate が取得できていない模様。(そもそも結果の XML に ReleaseDate が存在しない。一部の商品は ReleaseDate 取得できるけど、取得できない方が圧倒的に多い。)しかも、以前には確かに ReleaseDate が取得できていた商品も、なぜか取得できなくなってます。でも同じ商品でも、ECS4.0 ならちゃんと日付が取得できるんですよね。
で、問い合わせはディスカッションボードに投稿しろ、とここに書いてあったのでディスカッションボードを覗いてみても、どこから投稿していいのかさっぱり分からないし、あまり動きが活発でもなさそうで、素早い対応は期待できなさそう…そもそも AWS3.0 自体が古い API なわけだし、ということで、ECS4.0 対応のNet::Amazon::ECS をつくってみました。検索してみても公開されているものはなさそうだったので。(あったら誰か教えてください。)
といっても、とりあえず自分がやりたいこと(Plagger で発売日を iCal に Publish したり、今日・明日発売の商品情報をメールで飛ばしたり)に最低限必要な機能しか実装してないです。あと、今のところ CPAN にあげる予定はありません。
ついでに野良プラグインの CustomFeed::AmazonWebService を Net::Amazon::ECS に対応させた CustomFeed::AmazonECS もつくりました。
追記
なんかはてなの中の人が、ECS4.0 対応のモジュール作っていて、CPAN に up 予定らしい。なので近いうちにこれは必要なくなりそうですね。期待。
Net::Google::Calendar のパッチ
2006/10/01 18:22 追記
早速対応してくれました。「Domou Arigato」と書いてるのに笑った。http://pause.perl.org/incoming/ を見るとアップ済みのようなので、もうすぐ CPAN へ反映されると思います。
Net::Google::Calendar がまともに動かないので、パッチ書いた。
Index: Net-Google-Calendar-0.3/lib/Net/Google/Calendar.pm
===================================================================
--- Net-Google-Calendar-0.3/lib/Net/Google/Calendar.pm (revision 285)
+++ Net-Google-Calendar-0.3/lib/Net/Google/Calendar.pm (revision 286)
@@ -348,7 +348,9 @@
}
+ my $xml = $entry->as_xml;
+ _utf8_off($xml);
my %params = ( Content_Type => 'application/atom+xml; charset=UTF-8',
Authorization => "GoogleLogin auth=".$self->{_auth},
- Content => $entry->as_xml );
+ Content => $xml );
$params{'X-HTTP-Method-Override'} = $method unless "POST" eq $method;
@@ -381,4 +383,10 @@
}
+sub _utf8_off {
+ if ($] >= 5.008) {
+ require Encode;
+ return Encode::_utf8_off($_[0]);
+ }
+}
=head1 WARNING
Index: Net-Google-Calendar-0.3/lib/Net/Google/Calendar/Entry.pm
===================================================================
--- Net-Google-Calendar-0.3/lib/Net/Google/Calendar/Entry.pm (revision 285)
+++ Net-Google-Calendar-0.3/lib/Net/Google/Calendar/Entry.pm (revision 286)
@@ -54,5 +54,5 @@
my $self = shift;
- $self->category('', { scheme => 'http://schemas.google.com/g/2005#kind', term => 'http://schemas.google.com/g/2005#event' } );
+ $self->category( { scheme => 'http://schemas.google.com/g/2005#kind', term => 'http://schemas.google.com/g/2005#event' } );
$self->{_gd_ns} = XML::Atom::Namespace->new(gd => 'http://schemas.google.com/g/2005');
@@ -174,5 +174,5 @@
my($ns, $name, $attr) = @_;
my $ns_uri = ref($ns) eq 'XML::Atom::Namespace' ? $ns->{uri} : $ns;
- my $node = first($atom->{doc}, $ns_uri, $name);
+ my $node = first($atom->elem, $ns_uri, $name);
return $node unless defined $node && defined $attr;
my $val;
rt.cpan.org でレポートしておいた。
Using svk with plagger
うちでは 普段実行している plagger は本家 trunk から持ってきていて、自分で作ったプラグインは svn.mizzy.org に置いてあるのですが、以下の様なプロセスで開発してました。
- svn.mizzy.org からチェックアウトしたディレクトリに、俺プラグインを書いて置く。
- plagger 本家 trunk からチェックアウトしたディレクトリに、上記ディレクトリからファイルをコピーして、俺プラグインの動作テスト。
- テストが問題なければ、svn.mizzy.org に俺プラグインをコミット。
- 本家 trunk にコミットする場合は、svn co で コミットするファイルだけを指定。
2.のコピーがめんどくさくて、svk 使えばもっとエレガントになるんじゃないかな、と以前から思っていたのですが、使い方間違えると本家 trunk に余分なファイルまでコミットしてしまいそうで、怖くて使ってなかったのですが、色々試行錯誤してみて、こんな感じでいけそうだという感触がつかめたので、ここに整理しておきます。
準備
本家 trunk のローカルミラーとローカルブランチの作成
$ svk mirror //mirror/plagger-trunk http://svn.bulknews.net/repos/plagger/trunk/plagger $ svk sync //mirror/plagger-trunk --skipto HEAD $ svk cp -p //mirror/plagger-trunk //local/plagger-trunk
svn.mizzy.org のローカルミラーとローカルブランチの作成
$ svk mirror //mirror/plagger-mizzy http://svn.mizzy.org/public/plagger/trunk $ svk sync //mirror/plagger-mizzy $ svk cp //mirror/plagger-mizzy //local//plagger-mizzy
svk リポジトリの確認
$ svk list -R -d 1 // local/ plagger-mizzy/ plagger-trunk/ mirror/ plagger-mizzy/ plagger-trunk/
ローカルディレクトリにチェックアウト
$ mkdir svk [~] $ cd svk [~] $ svk co //local/plagger-trunk [~/svk] $ svk co //local/plagger-mizzy [~/svk] $ ls [~/svk] plagger-mizzy/ plagger-trunk/
プラグインの作成や修正など
プラグインを作ったり、修正したりして plagger-mizzy ローカルブランチにコミット
$ ./tools/plugin-start.pl Filter::Hoge [~/svk/plagger-mizzy] ... <プラグインを書く> ... $ svk commit [~/svk/plagger-mizzy]
つくったプラグインを plagger-trunk ローカルブランチとマージしてテスト
$ svk smerge -B //local/plagger-mizzy [~/svk/plagger-trunk] $ ./plagger -c test.yaml [~/svk/plagger-trunk]
プラグインに問題がなければ、plagger-mizzy ブランチの変更を svn.mizzy.org にコミット。一度 plagger-trunk とマージしてしまうと、なぜか svk push では svn.mizzy.org まで反映されなくなってしまったので、svk smerge 。
$ svk smerge //local/plagger-mizzy //mirror/plagger-mizzy
plagger 本家 trunk へのコミット
まだ試してないけど、こんな感じでできるはず。
$ svk commit files_to_commit [~/svk/plagger-trunk] $ svk push -C [~/svk/plagger-trunk] $ svk push --verbatim [~/svk/plagger-trunk]
余計なファイルまでコミットしてしまうと迷惑をかけてしまうので、-C をつけて確認する。
UPDATE: Shibuya.pm テクニカルトーク #7の発表資料 も併せてご参照ください。