さて、前回の続き、今回もPerlによる超手抜き家計簿の実装法を紹介する。
前回は、
2012-03-12 09:00「残高設定 5000円」
2012-03-12 12:00「ココイチ カレー 900円」
2012-03-12 10:00「ドトール コーヒー 150円」
2012-03-12 13:00「使途不明 100円」
というツイート列を、
日付 時刻 店舗 品目 金額 残高
2012-03-12 13:00 ? - 100円 3850円
2012-03-12 12:00 ココイチ カレー 900円 3950円
2012-03-12 10:00 ドトール コーヒー 150円 4850円
2012-03-12 09:00 残高設定 - 5000円 5000円
という家計簿に組み立てる仕様を実装した。
今回はこの仕様を実装する。
またプログラムをドバーンと公開する。
内容としては前回と一緒である。
実際に家計簿をパッと見たとき、一番上に最近のレコードが集まっている方が明らかに使いやすいからだ。
(もっともその上のpushをunshiftにすればいいような気もする)
ここではHTML::Templateというモジュールを使って、HTMLを生成している。
HTMLは、特に一覧画面のような表組みの画面がそうだが、形式が決まっていて、明細だけが変わるものが多い。
今作っている家計簿がその典型である。
で、このようなときに使うと便利なのがHTML::Templateモジュールである。
これは、プログラムとテンプレートファイルをセットで使う。
ここでは、kakeibo.tmplという外部ファイルにテンプレートを出している。
このファイルの中身は以下のようである。
で、このファイルを読み込む。
オブジェクトへのリファレンスを返すので、それを$tmplというスカラーで受ける。
これでもうファイルへは用なしだから速攻クローズしている。
ここで@sortへのリファレンスを代入している。
今、プログラム中で、@sortの各要素はdate、time、shop、item、cash、handというキー名の無名ハッシュリファレンスになっている。
このハッシュキー名が、テンプレートファイルのTMPL_VARタグのNAMEアトリビュートの名前と紐づいていて、各テーブル要素に変数の中身が展開されるようになっている。
今、家計簿の明細がこうなっているとすると、
2012-03-12 13:00 ? - 100円 3850円
2012-03-12 12:00 ココイチ カレー 900円 3950円
2012-03-12 10:00 ドトール コーヒー 150円 4850円
2012-03-12 09:00 残高設定 - 5000円 5000円
ハッシュ構造としてはこうなっている。
(スミマセン)。
次回はこのHTMLをメールで送るとする。
(つづく。次回最終回予定)
2012-03-12 09:00「残高設定 5000円」
2012-03-12 12:00「ココイチ カレー 900円」
2012-03-12 10:00「ドトール コーヒー 150円」
2012-03-12 13:00「使途不明 100円」
というツイート列を、
日付 時刻 店舗 品目 金額 残高
2012-03-12 13:00 ? - 100円 3850円
2012-03-12 12:00 ココイチ カレー 900円 3950円
2012-03-12 10:00 ドトール コーヒー 150円 4850円
2012-03-12 09:00 残高設定 - 5000円 5000円
という家計簿に組み立てる仕様を実装した。
今回はこの仕様を実装する。
またプログラムをドバーンと公開する。
内容としては前回と一緒である。
#!/usr/bin/perl -wさて、続きからまた説明する。
# mailHTML -- ツイッター家計簿アルファ版
use strict;
use Encode qw(from_to encode);
use Mail::Mailer;
use lib '/home/????????/local/lib';
use lib '/home/????????/local/lib/perl5';
use lib '/home/????????/local/lib/perl5/site_perl';
use Net::Twitter;
use utf8;
use DateTime::Format::Strptime;
use HTML::Template;
my $handle = Net::Twitter->new({
traits => [qw/OAuth API::REST API::Search/],
consumer_key => "????????",
consumer_secret => "????????",
access_token => "????????",
access_token_secret => "????????",
});
my $dt = DateTime->now( time_zone => 'Asia/Tokyo' );
$dt->subtract( days => 1 );
my $screen_name = '????????'; # アカウントのscreen name
my $statuses =
$handle->user_timeline({ id => $screen_name, count => 200, since => $dt });
my @out = ();
for my $status ( @$statuses ) {
my ($date, $time, $shop, $item, $cash);
my @tw = split / /, $status->{text};
for (@tw) {
if (/(\d\d\d\d-\d\d-\d\d)/) {
$date = $1;
} elsif (/(\d\d:\d\d)/) {
$time = $1.':00';
} elsif (/(\d+)円$/) {
$cash = $1;
} elsif (defined $shop) {
$item = $_;
} else {
$shop = $_;
}
}
next unless defined $cash;
my ($nowdate, $nowtime) = &tzChange($status->{created_at});
$date = $nowdate unless defined $date;
$time = $nowtime unless defined $time;
$item = "-" unless defined $item;
$shop = "?" unless defined $shop;
push @out, { date=> $date, time => $time, shop => $shop, item => $item, cash => $cash };
}
my $zan;
my @sort;
for my $out (sort {$a->{date}.$a->{time} cmp $b->{date}.$b->{time}} @out) {
if ($out->{shop} eq '残高設定') {
$zan = $out->{cash};
} elsif (defined $zan) {
$zan -= $out->{cash};
} else {
next;
}
$out->{hand} = $zan;
push @sort, $out;
} # ★★★ここまで説明した★★
@sort = reverse @sort;
my $tmpl_file = "kakeibo.tmpl";
my $tmpl;
open (my $template, "<:utf8", $tmpl_file );
$tmpl = HTML::Template->new(filehandle => *$template);
close $template;
$tmpl->param( { Table => \@sort } );
my $from = 'from@example.com';
my $to = '?????@example.com';
my $subject = "家計簿";
my $mailer = Mail::Mailer->new("sendmail");
$mailer->open({ From => $from,
To => $to,
Subject => $subject,
'MIME-Version' => '1.0',
'Content-Type' => "text/html; charset=UTF-8",
'Content-Transfer-Encoding' => '8bit',
}) or die "Can't open $!\n";
print $mailer $tmpl->output;
$mailer->close();
sub tzChange ($) {
my $utc = shift;
#Sat Feb 11 03:54:53 +0000 2012
my $strp = DateTime::Format::Strptime->new(
pattern => '%a %b %d %H:%M:%S %z %Y'
);
my $dt = $strp->parse_datetime($utc);
$dt->set_time_zone('Asia/Tokyo');
return ($dt->strftime("%Y-%m-%d"), $dt->strftime("%H:%M:%S"));
}
@sort = reverse @sort;現在配列@sortには明細が時間昇順で(過去から未来に向かって)入っているので、これを反転させて、一番最近の明細を上に持ってくる。
実際に家計簿をパッと見たとき、一番上に最近のレコードが集まっている方が明らかに使いやすいからだ。
(もっともその上のpushをunshiftにすればいいような気もする)
my $tmpl_file = "kakeibo.tmpl";さて、ここが問題である。
my $tmpl;
open (my $template, "<:utf8", $tmpl_file );
$tmpl = HTML::Template->new(filehandle => *$template);
close $template;
ここではHTML::Templateというモジュールを使って、HTMLを生成している。
HTMLは、特に一覧画面のような表組みの画面がそうだが、形式が決まっていて、明細だけが変わるものが多い。
今作っている家計簿がその典型である。
で、このようなときに使うと便利なのがHTML::Templateモジュールである。
これは、プログラムとテンプレートファイルをセットで使う。
ここでは、kakeibo.tmplという外部ファイルにテンプレートを出している。
このファイルの中身は以下のようである。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"内容は、ほとんどHTMLだが、TMPL_LOOPと、TMPL_VARの2つのタグが見せ場である。
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=980,initial-scale=1.0,user-scalable=yes,maximum-scale=3.0" />
<title>Booky!</title>
</head>
<body>
<table BORDER>
<tr>
<th>日付</th><th>時刻</th><th>店舗</th><th>品目</th><th>金額</th><th>残高</th>
</tr>
<TMPL_LOOP NAME=Table>
<tr>
<td><TMPL_VAR NAME=Date></td>
<td><TMPL_VAR NAME=Time></td>
<td><TMPL_VAR NAME=Shop></td>
<td><TMPL_VAR NAME=Item></td>
<td><TMPL_VAR NAME=Cash></td>
<td><TMPL_VAR NAME=Hand></td>
</tr>
</TMPL_LOOP>
</table>
</body>
</html>
で、このファイルを読み込む。
$tmpl = HTML::Template->new(filehandle => *$template);newHTML::Templateオブジェクトのコンストラクタであり、引数にファイルハンドルへの型ブログを渡す。
オブジェクトへのリファレンスを返すので、それを$tmplというスカラーで受ける。
これでもうファイルへは用なしだから速攻クローズしている。
$tmpl->param( { Table => \@sort } );ここで、$tmplオブジェクトのparamメソッドを呼び出して、テンプレートの中の表組に値をセットしている。
ここで@sortへのリファレンスを代入している。
今、プログラム中で、@sortの各要素はdate、time、shop、item、cash、handというキー名の無名ハッシュリファレンスになっている。
このハッシュキー名が、テンプレートファイルのTMPL_VARタグのNAMEアトリビュートの名前と紐づいていて、各テーブル要素に変数の中身が展開されるようになっている。
今、家計簿の明細がこうなっているとすると、
2012-03-12 13:00 ? - 100円 3850円
2012-03-12 12:00 ココイチ カレー 900円 3950円
2012-03-12 10:00 ドトール コーヒー 150円 4850円
2012-03-12 09:00 残高設定 - 5000円 5000円
ハッシュ構造としてはこうなっている。
@sort = (で、これを$tmpl->paramメソッドで渡すと、以下のようなHTMLに展開される。
{ date => "2012-03-12", time => "13:00", shop => "?", item => "-", cash => "100", hand => "3850" },
{ date => "2012-03-12", time => "12:00", shop => "ココイチ", item => "カレー", cash => "800", hand => "3950" },
・・・略・・・
);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"詳しい説明はHTML::Templateのperldocに譲るとして、このように動的なHTMLを短いプログラムで作れる雰囲気だけ感じて欲しい。
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=980,initial-scale=1.0,user-scalable=yes,maximum-scale=3.0" />
<title>Booky!</title>
</head>
<body>
<table BORDER>
<tr>
<th>日付</th><th>時刻</th><th>店舗</th><th>品目</th><th>金額</th><th>残高</th>
</tr>
<tr>
<td><2012-03-12></td>
<td><13:00></td>
<td><?></td>
<td><-></td>
<td><100></td>
<td><3850></td>
</tr>
<tr>
<td><2012-03-12></td>
<td><12:00></td>
<td><ココイチ></td>
<td><カレー></td>
<td><900></td>
<td><3950></td>
</tr>
・・・略・・・
</table>
</body>
</html>
(スミマセン)。
次回はこのHTMLをメールで送るとする。
(つづく。次回最終回予定)