Home > Archives > 2009-07
2009-07
Email::MIMEの生成をtemplateエンジン経由で行ってくれるEmail::MIME::Kitがいい感じ
- 2009-07-12 (日)
- perl
Email::MIME::Kitがいい感じです。内部ではEmail::MIME::Creatorを使っているのですが、MIME::LiteでいうところのMIME::Lite::TTのようなもので、更にheaderに関してもtemplateで書けます。
素のEmail::MIME::Creatorで
use strict;
use warnings;
use utf8;
use Encode;
use Email::MIME;
use Email::MIME::Creator;
use Email::Send;
use Template;
my $t = Template->new({ENCODING => 'UTF-8'});
my $mydata = {hoge => 'aaa'};
$t->process('subject.tt', $mydata, \my $subject);
$t->process('body.tt', $mydata, \my $body);
my $mail = Email::MIME->create(
header => [
From => 'chiba+from@geminium.com',
To => 'chiba+to@geminium.com',
Subject => Encode::encode('MIME-Header', $subject),
],
attributes => {
content_type => 'text/plain',
charset => 'UTF-8',
},
body => $body,
);
my $sender = Email::Send->new({mailer => 'SMTP', mailer_args => [Host => 'localhost']});
$sender->send($mail);
って感じで書いてたものをEmail::MIME::Kitを使うと
use strict;
use warnings;
use utf8;
use Email::Send;
use Email::MIME::Kit;
my $sender = Email::Send->new({mailer => 'SMTP', mailer_args => [Host => 'localhost'] });
my $kit = Email::MIME::Kit->new({
manifest_reader => 'YAML',
source => 'mkit/',
});
$sender->send(
$kit->assemble({
hoge => 'fuga',
})
);
という感じでシンプルに書けます。
mkit/manifest.yamlにはこんな感じで設定を書いておくと、body.ttが自動で読み込まれますし、headerの部分は外部ファイルにはできませんがTT書式で書けます。ここではrendererとしてTTを指定していますが、MicroMason、Text::TemplateあたりはCPANにアップされています。
renderer: TT header: - Subject: 'てすと[% hoge %]' - From: 'Masahiro Chiba <chiba+from@geminium.com>' - To: 'Masahiro Chiba <chiba+to@geminium.com>' attributes: content_type: text/plain charset: UTF-8 path: body.tt
マルチバイト文字コードはUTF-8のことしかほぼ考えられてないみたいなのでISO-2022-JPじゃないとだめだーって人は自分でEmail::MIME::Kit::Role::Assemblerの継承クラスを定義するといいと思います。Mooooseなモジュールなのでモダンに書けます。
で、標準のTTのrenderでちょっと不満だったのがprocessに渡されるのがテンプレートファイルの中身のリファレンスで、これだとTTがコンパイル結果をキャッシュしてくれないんですよね。ファイル名で渡しておくとキャッシュしてくれる。なのでpathが指定されている場合はrendererにpathをそのままスルーしてくれるAssemblerを書いてみました。
package Email::MIME::Kit::Assembler::PathThrough;
use Moose;
extends 'Email::MIME::Kit::Assembler::Standard';
with 'Email::MIME::Kit::Role::Assembler';
our $VERSION = '1.00';
use Template;
override '_assemble_from_kit' => sub {
my ($self, $stash) = @_;
my $fullpath = File::Spec->catfile($self->kit->source, $self->manifest->{path});
my $body_ref = $self->render($fullpath, $stash);
my %attr = %{ $self->manifest->{attributes} || {} };
$attr{content_type} = $attr{content_type} || 'text/plain';
if ($$body_ref =~ /[\x80-\xff]/) {
$attr{encoding} ||= 'quoted-printable';
$attr{charset} ||= 'utf-8';
}
my $email = $self->_contain_attachments({
attributes => \%attr,
header => $self->manifest->{header},
stash => $stash,
body => $$body_ref,
container_type => $self->manifest->{container_type},
});
};
after '_set_renderer' => sub {
my $self = shift;
$self->renderer->_tt(
Template->new({
ABSOLUTE => 1,
ENCODING => 'UTF-8',
}),
);
};
no Moose;
1;
まぁやっぱりUTF-8前提だったりします。
manifestにはこんな感じで「assembler: PathThrough」を追加しておきます。
assembler: PathThrough renderer: TT header: - Subject: 'てすと[% hoge %]' - From: 'Masahiro Chiba <chiba+from@geminium.com>' - To: 'Masahiro Chiba <chiba+to@geminium.com>' attributes: content_type: text/plain charset: UTF-8 path: body.tt
- Comments: 0
- Trackbacks: 0
HTML::FillInForm::Liteの使いどころ
- 2009-07-12 (日)
- perl
正規表現でHTML::FillInFormを実現しているHTML::FillInForm::Liteを最近つかっています。HTML::FillInFormの機能に加え、任意のオブジェクトを渡してそのアクセサからデータを取得してくれるため、DBIx::Class::AsFdatなどのモジュールを使わずに、DBICのrowデータをそのままfillinできるのがうれしかったりします。また、パラメータの取得方法部分もHTML::FillInFormよりも比較的拡張しやすくなっているので便利です。
ただ、性能がHTML::FillInFormよりもいいかというと自分の環境下やデータではそうでもなかったりして、特に大きいhtmlデータが対象だとかなり性能が劣化するようです。formのidをtargetで指定してあげることで大分緩和されますがHTML::FillInFromとの差は歴然としてあるようです。
そこで、C::P::FillInFormのようにhtml全体を対象とするのではなく、TTのフィルターを使ってfillinしてみました。
こんな感じでFILTERを定義して、
my $t = Template->new({
ENCODING => 'UTF-8',
FILTERS => {
fillinform => [\&fillinform, 1],
},
});
my $f = HTML::FillInForm::Lite->new;
sub fillinform {
my ($context, $data, @options) = @_;
return sub {
my $html = shift;
$f->fill(\$html, $data, @options);
};
}
テンプレートの中ではこんな風に使います。
[% FILTER fillinform(filldata) %]<form>...</form>[% END %]
formの部分は別ファイルにしておくとこんなふうにシンプルにかけるのがいい感じです。
[% INCLUDE parts/form.tt | fillinform(filldata) %]
fillinformってのはCではなくてVの仕事なんじゃないかとも思うのでこちらのほうがわかりやすいような気もしてきてます。
で、最後にベンチマークをのっけておきます。全体のfillinと局所化したものがだいぶ差があるのがわかると思います。また、それでもHTML::FillInFormに勝てていませんが、大分差も縮まっています。
use strict;
use warnings;
use utf8;
binmode STDOUT, ':utf8';
use Benchmark qw/cmpthese/;
use Template;
use HTML::FillInForm;
use HTML::FillInForm::Lite;
my $t = Template->new({
ENCODING => 'UTF-8',
FILTERS => {
fillinform => [\&fillinform, 1],
fillinformlite => [\&fillinformlite, 1],
},
});
my $f = HTML::FillInForm->new;
my $fl = HTML::FillInForm::Lite->new;
my $filldata = {mail => 'chiba@geminium.com', name => '千葉征弘', tel => '03-3419-2801'};
cmpthese(5000, {
fillinall => sub {
$t->process('test.html', {
hoge => 'aha'
}, \my $output);
$f->fill(\$output, $filldata);
},
fillinpart => sub {
$t->process('test_part.html', {
hoge => 'aha',
filldata => $filldata,
}, \my $output);
},
fillinall_lite => sub {
$t->process('test.html', {
hoge => 'aha'
}, \my $output);
$fl->fill(\$output, $filldata);
},
fillinpart_lite => sub {
$t->process('test_part_lite.html', {
hoge => 'aha',
filldata => $filldata,
}, \my $output);
},
});
sub fillinform {
my ($context, $data, @options) = @_;
return sub {
my $html = shift;
$f->fill(\$html, $data, @options);
};
}
sub fillinformlite {
my ($context, $data, @options) = @_;
return sub {
my $html = shift;
$fl->fill(\$html, $data, @options);
};
}
test.html
test_part.html
test_part_lite.html
結果
Rate fillinall_lite fillinall fillinpart_lite fillinpart
fillinall_lite 274/s -- -62% -76% -77%
fillinall 729/s 166% -- -36% -40%
fillinpart_lite 1136/s 315% 56% -- -6%
fillinpart 1208/s 341% 66% 6% --
- Comments: 0
- Trackbacks: 1
Catalyst::Develを1.16以上にUpgradeしたとき
- 2009-07-12 (日)
- perl
catalystのstandaloneサーバを-r付きで使っている人はCatalyst::Develを1.16以上にUpgradeしたときは
catalyst.pl -force -scripts MyApp
を自分のmy appディレクトリで実行すること。しないと_kill_childメソッドが無いとかエラーがでます。
- Comments: 0
- Trackbacks: 0
Home > Archives > 2009-07
- Search
- Feeds
- Meta