• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
perl casual #4 大改造!! Perl劇的ビフォーアフター
 

perl casual #4 大改造!! Perl劇的ビフォーアフター

on

  • 1,730 views

http://cpanbook.koneta.org/post/5027293272/perl-casual-4

http://cpanbook.koneta.org/post/5027293272/perl-casual-4

Statistics

Views

Total Views
1,730
Views on SlideShare
1,728
Embed Views
2

Actions

Likes
0
Downloads
0
Comments
0

1 Embed 2

http://orhowilearnedtolovetheperl.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    perl casual #4 大改造!! Perl劇的ビフォーアフター perl casual #4 大改造!! Perl劇的ビフォーアフター Presentation Transcript

    • 本が出ました• m(__)m
    • CONFIDENTIAL @tomitaPerl Casual #4 @tomita
    • アジェンダ• 物件1: バッチ処理• 物件2: メール送信フォーム の使い⽅紹介
    • 物件1 バッチ処理 1
    • $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • 0 0 1 * * cd /home/app/; perl batch/dump.pl
    • 改善したい点• 動くのだけど・・・
    • $dbuser = company-batch;$dbpass = company-batch-pass;use DBI; パスワードをスクリ$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = プトに書きたくない localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass); 前⽉指定が怪しい。$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry あと引数で任意の⽉ WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month); を指定したいopen FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass); 自作CSV出⼒部分の$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry 不安 WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安• を置いておいて
    • 潜在的な問題
    • p.12
    • $dbuser = company-batch;$dbpass = company-batch-pass;use DBI; use strict;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = use warnings; localtime($month); がない = ケアレス$month = sprintf("%4d%02d", $year+1900, $mon);$db =$st = ミスの可能性 DBI->connect(dbi:mysql:company, $dbuser, $dbpass); $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • $dbuser = company-batch; 例外処理不⾜$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • $dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7; ⽇本語を含む値($sec, $min, $hour, $mday, $mon, $year) = だった場合 localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);open FH, "> $month.csv";while (my $row = $st->fetchrow_arrayref) { print FH join ",", @$row; print FH "¥r¥n";}
    • 潜在的な問題• use strict; use warnings; がない ←• 例外処理不⾜• ⽇本語を含む値だった場合
    • use strictuse warnings;$dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section
    • perl -c> perl –c dump.plGlobal symbol "$dbuser" requires explicit package name atdump.pl line 5
    • 潜在的な問題• use strict; use warnings; がない• 例外処理不⾜ ←• ⽇本語を含む値だった場合
    • p.246, 247 PRポイント: 全編falseを返すのか、 例外を返すのか、例 外を返すにはどうし たらよいのかを触れ ている
    • p.15
    • use strictuse warnings;use autodie; autodie;my $dbuser = company-batch;my $dbpass = company-batch-pass;use DBI;my $month = time - 60*60*24*7;my ($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);my $db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass,{ RaiseError => 1,});my $st = $db->prepare(q{
    • MAILTO=admin@example.com0 0 1 * * cd /home/app/; perl batch/dump.pl
    • 潜在的な問題• use strict; use warnings; がない• 例外処理不⾜• ⽇本語を含む値だった場合 ←
    • p.248 DBI DBI PRポイント: 全編を通して”⽂字列” を受け取るのか、返 すのかに触れている
    • p.11 凡例
    • my $db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass,{ RaiseError => 1, mysql_enable_utf8 => 1,});...open(my $fh, >:encoding(cp932), $filename); open()の使い⽅ですが openモジュールの項目 で解説しています
    • 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安
    • 設定ファイルJSON形式YAML形式INI形式XML形式
    • p.223 App::Options
    • 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安
    • use strict;use warnings;use autodie;use DBI; App::Options(use App::Options( option => { filename_format => { ./%s.csv s.csv default => ./%s.csv }, dbuser => { required => 1 }, dbpass => { required => 1 }, month => { required => 1, type => /^20¥d{4}$/ }, /^20¥ });my $db = DBI->connect(dbi:mysql:company, $App::options{dbuser}, App::options{dbuser} $App::options{dbpass}, App::options{dbpass} { RaiseError => 1, mysql_enable_utf8 => 1, },);
    • •dump.confdbuser = company-batchdbpass = company-batch-pass> perl dump.pl --month=201103 --helpUsage: dump.pl [options] [args] --help print this message --dbpass=<value> [********] --dbuser=<value> [company-batch] --filename_format=<value> [./%s.csv] --month=<value> [201103] (/^20¥d{4}$/)
    • 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。 ←• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安
    • p.95-p.95- Time::Piece
    • Time::Piece Piece;use Time::Piece;use Time::Seconds; Time::Seconds;use App::Options( option => { filename_format => { default => ./%s.csv }, dbuser => { required => 1 }, dbpass => { required => 1 }, month => { type => /^20¥d{4}$/, default => do { localtime; my $d = localtime; $d- month_last_day; $d -= ONE_DAY * $d->month_last_day; $d- strftime(%Y%m); $d->strftime(%Y%m); }, }, });my $db = DBI->connect(dbi:mysql:company,
    • 改善したい点• パスワードをスクリプトに書きたくな い• 前⽉指定が怪しい。• あと引数で任意の⽉を指定したい• 自作CSV出⼒部分の不安 ←
    • p.202 Text::CSV
    • my $rows = $db->selectall_arrayref(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section}, {}, $App::options{month},);my $filename = sprintf $App::options{filename_format}, $App::options{month};open(my $fh, >:encoding(cp932), $filename); $csv Text::CSV-my $csv = Text::CSV->new({ auto_diag => 1, binary => 1, eol => "¥r¥n", "¥});$csv->print($fh, $_) for @$rows; csv- print($fh,
    • なんということでしょう〜•before$dbuser = company-batch;$dbpass = company-batch-pass;use DBI;$month = time - 60*60*24*7;($sec, $min, $hour, $mday, $mon, $year) = localtime($month);$month = sprintf("%4d%02d", $year+1900, $mon);$db = DBI->connect(dbi:mysql:company, $dbuser, $dbpass);$st = $db->prepare(q{ SELECT section, COUNT(*) AS count FROM inquiry WHERE DATE_FORMAT(ctime, "%Y%m") = ? GROUP BY section});$st->execute($month);
    • なんということでしょう〜•afteruse strict;use warnings; https://gist.github.com/956691use autodie;use DBI;use Text::CSV;use Time::Piece;use Time::Seconds;use App::Options( option => { filename_format => { default => ./%s.csv }, dbuser => { required => 1 }, dbpass => { required => 1 }, month => { type => /^20¥d{4}$/, default => do { my $d = localtime;
    • 導⼊したモジュール• strict• warnings• autodie• Text::CSV• Time::Piece• App::Options
    • モジュールのインストール• → p.421- App::cpanminus
    • App::cpanminusの項目で取り上げてApp::cpanminusいる内容• cpanmコマンド自体の導⼊⽅法• インストールパスの確認⽅法• 特定のディレクトリにインストールす る⽅法(ユーザー権限で)• インストール失敗時のトラブルシュー ティング
    • > cpanm -l extlib autodie Text::CSV Time::Piece App::Optionsuse strict;use warnings;use FindBin; FindBin;use lib "$FindBin::Bin/extlib/lib/perl5";use autodie;use DBI;use Text::CSV;use Time::Piece;use App::Options(> perl -Mlib="extlib/lib/perl5/" dump.cgi
    • 物件2 メール送信フォーム 2
    • 割愛
    • 割愛
    • 1ページ目のサンプルがほとんど• strict/warningsに通らない• jcode.pl付属(2005年以前?)• メールのソースを⼿作り• 自作のバリデーション• エラー⽂⾔が送信プログラムに書いてある• ※だめというわけではありません
    • 改造• というよりは作り直しの例
    • サーバー サーバー・バリデーション ・バリデーション ・処理(メール送信)
    • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="stylesheet" href="http://static.koneta.org/base.css" type="text/css" /><title>お問い合わせフォーム</title></head><body><h1>お問い合わせフォーム</h1> https://gist.github.com/956691<form method="post" id="form"> <p>お名前<br /> <input type="text" class="input text" name="name" /></p> <p>メールアドレス<br /> <input type="text" class="input text ascii" name="email" /></p> <p>お問い合わせ内容<br /> <textarea class="input" name="comment"></textarea></p> <p class="notice message hide">入力内容を確認してください。</p> <p class="error message hide">送信失敗しました。info@koneta.orgまで送信願います。</p> <p class="information message hide step2">この内容で送信してもよいですか?</p> <button type="submit" class="step1" value="2">確認</button> <button type="submit" class="step2 hide" value="1">修正</button> <button type="submit" class="step2 hide" value="3">送信</button></form> <p class="success message hide step3">お問い合わせありがとうございました。</p></body></html>
    • サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成• メール送信• 割愛: トークン、丁寧なエラー
    • サーバーサイド• JSON作成 ←• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成• メール送信
    • p.180 JSON
    • use JSON;my $res = { version => 1.1 };if (my $error = validate($req)) { $res->{error} = $error;}if ($res->{validate} and $req->param(step) eq submit) { $res->{result} = sendmail($req);} encode_json($res);my $body = encode_json($res);
    • サーバーサイド• JSON作成• JSON RPC サーバー ←• ⼊⼒値バリデーション• メール作成• メール送信
    • Plack::Request;use Plack::Request;my $app = sub { $req Plack::Request- new(shift); my $req = Plack::Request->new(shift); my $res = { version => 1.1 }; if (my $error = validate($req)) { $res->{error} = $error; } if ($res->{validate} and $req->param(step) eq submit) { $res->{result} = sendmail($req); } my $body = encode_json($res); return [ 200, Content- application/json json [ Content-Type => application/json ], [ $body ], ];};
    • なんということでしょう〜•before 割愛
    • なんということでしょう〜•afteruse strict;use wanings;use JSON https://gist.github.com/956691use Plack::Request;my $app = sub { my $req = Plack::Request->new(shift); my $res = { version => 1.1 }; if (my $error = validate($req)) { $res->{error} = $error; } if ($res->{validate} and $req->param(step) eq submit) { $res->{result} = sendmail($req); }
    • p.334, 335 Plack
    • サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション ←• メール作成• メール送信
    • p.346 FormValidator::Lite• おすすめ理由 http://d.hatena.ne.jp/tomi-ru/20110119/1295394476
    • なんということでしょう〜•before 割愛
    • •after qw/Email/;use FormValidator::Lite qw/Email/;sub validate { my ($req) = @_; ($req) req FormValidator::Lite- new($req); my $form = FormValidator::Lite->new($req); $form- $form->check( email => [REQUIRED, EMAIL], comment => [REQUIRED], ); $form- has_error; return unless $form->has_error; return { name ValidateError ValidateError, => ValidateError, code => 100, message => Validate Error, };}
    • サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成 ←• メール送信
    • なんということでしょう〜•before 割愛
    • •afteruse utf8;use Encode;use Email::MIME; Email::MIME; Email::MIME-my $email = Email::MIME->create( header => [ From => $req->param(email), $req param(email), req- To info@koneta.org info@koneta.org, => info@koneta.org, Subject => [問い合わせフォーム], [問 わせフォーム], フォーム ], attributes => { charset iso-2022- => iso-2022-jp, encoding => 7bit, }, sprintf( body_str => sprintf( "[Name]¥n%s¥ n[Comment]¥n%s", "[Name]¥n%s¥n¥n[Comment]¥n%s", $encoding- $req param(name) req- $encoding->decode( $req->param(name) ), $encoding- $encoding->decode( $req->param(comment) ), $req param(comment) req- ),);
    • サーバーサイド• JSON作成• JSON RPC サーバー• ⼊⼒値バリデーション• メール作成• メール送信 ←
    • なんということでしょう〜•before 割愛
    • •afteruse Email::Send; Email::Send;my $sender = Email::Send->new({ mailer => Sendmail }); Email::Send- Sendmail Sendmail$sender- send($email)$sender->send($email) or die "send() failed!";
    • CONFIDENTIALありがとうございました。
    • • http://twitter.com/tomita
    • One More• ⼀⽅ロシアは・・・• テスト