Alligator Swamp

技術メモ

YAPC::Asia Tokyo 2015 に行ってきた

1日目(+懇親会)、2日目と参加してきた。 参加したトークは以下。

同時通訳はトーク動画には入らないと思ったので、迷った時は海外ゲストのトークを聞きに行った。同時通訳最高でした。後はPerl6のトークも優先した。

Larry Wall氏のトークで、Perl6のリリース時期が2015年のクリスマスと発言されたのもあって、Perl6に俄然興味が出てきた。Jonathan Worthington氏の、Perl6の並行/並列/非同期処理の話もとても興味深かった。

コミケに行かなかったので手に入れられなかった「雅なPerl入門第3版」がありがたいことに頒布されていたので購入。こちらにもPerl6入門の章があったので、リリース前に入門してみようと思う。

懇親会では、今までは基本的に知り合いと話すのがメインだったが、今回は初めて合う人と話をすることが多く、内容も充実していて、とても有意義だった。

ある範囲内の日付時刻を、指定間隔で反復するTime::Piece::Iteratorというモジュールを作った

この記事はPerl Advent Calendar 2014の18日目の記事です。

17日目の記事はid:kfly8さんの間接オブジェクト記法のアンチパターンでした。

Time::Piece::Iterator

Time::Piece::Iterator

指定した範囲内の日付時刻を、指定した間隔で反復するモジュールが欲しかったのですが、見つからなかったので作成しました。(他にあれば教えて下さい!)
日付とか年月を引数に取るバッチを、特定の期間分(半年とか)実行したい時に使ってます。

使い方

Time::Pieceオブジェクトを2つ渡すと、その範囲内の日付時刻を返してくれます。

use Time::Piece;
use Time::Piece::Iterator;

my $iterator = day_iterator(
    localtime->strptime('2014/01/01', '%Y/%m/%d'),
    localtime->strptime('2014/01/03', '%Y/%m/%d'),
);

while( my $t = $iterator->next ) {
    print $t->ymd, "\n";
}
2014-01-01
2014-01-02
2014-01-03

間隔はdayだけではなくsecond/minute/hour/week/month/yearを用意しています。
例えば、今年の各月最初の平日を知りたい場合はこんなかんじです。

use Time::Piece;
use Time::Piece::Iterator;
use Time::Seconds;
use Calendar::Japanese::Holiday;

sub is_weekday {
    my $t = shift;
    my $is_holiday = isHoliday( $t->year, $t->mon, $t->mday, 1 );
    if( $is_holiday || $t->wday == 1 || $t->wday == 7 ) {
        return 0;
    }
    return 1;
}

my $from = localtime->strptime('2014-01-01', '%Y-%m-%d');
my $to = $from->add_years(1) - ONE_DAY;

my $iterator = month_iterator( $from, $to );
while( my $t = $iterator->next ) {
    while( !is_weekday($t) ) {
        $t += ONE_DAY;
    }
    print $t->ymd, "\n";
}

用意されている間隔では要件が満たせない場合は、自分で設定することが出来ます。
以下の例は、間隔が3週間の場合です。

my $iterator = custom_iterator(
    $from, $to,
    sub {
        my ($t, $sign) = @_;
        return $t + ( $sign * 3 * ONE_WEEK );
    }
);

第1引数が現在の日付時刻、第2引数が符号(plus or minus)です。過去に遡ることも出来るので、符号を受け取れるようにしています。

注意点

month_iteratorとyear_iteratorはTime::Pieceのadd_monthsとadd_yearsを使っているので、月末の扱いに注意する必要があります。

今後

無限iteratorを可能にする、Time::Piece::Plusも扱えるようにする、などを考えています。

あと、CPANには上げていないのですが、使っていただける方がいれば上げたいなと思っています。

明日

19日目はid:y_uukiさんです!

Chiba.pm #5 に行ってきた #chibapm

Chiba.pm #5に参加し、LTもして来ました。
初めてこういった場でLTをさせて頂いたので、とても緊張しましたが、良い経験になりました。

(reveal.jsで作った資料をPDFエクスポートしたらレイアウト崩れてしまいました)

内容は、最近使っているPath::Tinyというモジュールについての紹介とハマったことです。

感想

メイントークが「MySQLの歴史」と「職業訓練」でPerlが一切出てこなくて驚きましたが、どちらもとても興味深く面白い内容でした!
特にMySQLの歴史についてのトークは、業務でMySQLのバージョンアップ対応をやっていたこともあり、それについての知見が得られたのは嬉しい誤算でした。

主催者の@kaztrさん、@8GRTさん、ありがとうございました&お疲れ様でした!

YAPC::Asia 2014に参加してきた #yapcasia

去年初めて参加したYAPC::Asia。2回目の参加です。
ちゃんと感想を書いて、今年のYAPCを終えようと思います。

印象に残ったセッション

Releasing perl

ドキュメントの充実や開発プロセスの簡略化にかなり力を入れていて、 長く続けていくにはこういった地道な努力が必要なんだと思わされました。

お待たせしました。Perl で BDD を簡単に実践する最高にクールなフレームワークができました

Test::More 2.0が開発中止になっていたとは...。Test::Kantan使ってみます!

Perl::Lint - Yet Another Perl Source Code Linter

トークンとはどういうものなのか、どういった処理でチェックを行っているかの説明が理解しやすかったです。プロジェクトごとのポリシーも作れる(作りやすい)とのことなので(複雑でなければ)、業務に活かせそうで楽しみです!

WHERE狙いのキー、ORDER BY狙いのキー

何故クエリが遅くなるのか早くなるのかをPerlのコードを用いて説明されていて、Perl使いにはありがたいです。Indexはソート済みなのでそれを狙ってクエリの高速化を行うなど、具体的なやり方を説明しているのがとても良かった。
理解する前に進んでしまったところが一部あったので、スライドを見直そうと思います!

オープンソースの開発現場 - Perl 5.20 のSubroutine Signaturesが来るまでの奮闘の軌跡

Peter Martini氏がいい男過ぎてもう......。最終的に全部書きなおされたのに、入った事自体がいい事なんだ、なんて俺は言えないだろうな......。
海外のこういった事例が聞けるのは本当に貴重でありがたいセッションでした。

半端なPHPDisでPHPerに陰で笑われないためのPerl Monger向け最新PHP事情(5.6対応)

トークが抜群に上手く、聴衆が一気に引きこまれてました...!ネタ(闇)も交えてPHPの魅力が語られていて、やってみようかなという気にさせてくれるとても素晴らしい内容でした。
ベストトーク賞1位おめでとうございます!

Perlあるある

憧れのハッカーの方々についての、普段聞けないようなことが聞ける貴重なトークでしたw 時間の都合で答えられていなかった質問の回答がとても気になります!

YAPC::Europe 2014 に行ってきました

ビール天国に行きたい!そしてOAuth認証のLTが面白いw
Google翻訳でも何とかなるというお話は、躊躇している人にとってはとても良い情報だと思いました。

Perlの静的解析入門とPerlリファクタリングツールApp::PRTのご紹介

独特なテンポのトークがとても面白かった!
しかも内容はかなり実用的で、これは実践せねばと思いました!

キーノート

「一度の人生楽しまなきゃ損!」
最高でした。

設備など

コーヒー、ジュース、お菓子、レッドブル、かき氷が無料で提供され、懇親会は無料、HUBは貸し切りで1000杯までフリードリンクという至れり尽くせりで、正直このチケット価格で大丈夫かな...と心配になります。

イベントホールでは書籍の販売やイベントトラックがあったり、とても賑やかな感じでお祭りのようでした。

会場のネットワークは快適過ぎて最高でした。

その他

懇親会で出身地が同じ方と偶然出会い、地元トークや、色々共通点がある過去の(ヤバイ)プロジェクト話で大いに盛り上がり、とても楽しい時間を過ごすことが出来ました。こういった出会いもあるYAPCは本当に素晴らしいですね。

まとめ

運営の方々、本当にお疲れ様でした!最高です!
次回は登壇する側に立ってみたいです!

Capture::Tinyを使ってSTDERRに何も出力されていないことをテストする

経緯

  1. 数千万行あるファイルに対して1行ごとに処理するようなバッチを書く
  2. utf8フラグ付きの文字列をencode_utf8せずに処理してしまう
  3. 大量のWide character in ...という警告がログに出力される
  4. 気付かずに本番リリースされ、それが原因で障害発生
  5. 悲しみに閉ざされる

対策

あれ以来、テストでSTDERRのチェックを行うようにしている。
あと、テストデータにマルチバイト文字列を忘れずに入れる。

my ($stdout, $stderr, $exit) = capture { MyApp->new->run(@argv) };
is $stderr, '', '標準エラー出力には何も出力されていない';

Path::ClassからPath::Tinyに移行した時に書き換えた処理

バージョン

  • Path::Class 0.33
  • Path::Tiny 0.056

オブジェクト生成

Path::Classで生成したオブジェクトは、ファイルはPath::Class::File、ディレクトリはPath::Class::Dirとなる。Path::TinyはどちらもPath::Tinyとなる。

# Path::Class
$file = file($path);
$dir  = dir($path);

# Path::Tiny
$file = path($path);
$dir  = path($path);

ディレクトリ配下のファイルオブジェクト生成

# Path::Class
$file = $dir->file($name);

# Path::Tiny
$file = $dir->child($name);

ディレクトリ配下のディレクトリオブジェクト生成

# Path::Class
$dir = $dir->subdir($name);

# Path::Tiny
$dir = $dir->child($name);

ディレクトリ削除(配下ファイルごと)

# Path::Class
$dir->rmtree;

# Path::Tiny
$dir->remove_tree;

ファイルオープン

# Path::Class
$read = $file->openr;
$read = $file->open('<:encoding(cp932)') or die "Can't read $file: $!";
$read = $file->open('<:utf8') or die "Can't read $file: $!";

# Path::Tiny
$read = $file->openr;
$read = $file->openr(':encoding(cp932)');
$read = $file->openr_utf8;

ファイルの内容を配列に読み込み

# Path::Class
@lines = $file->slurp( chomp => 1 );

# Path::Tiny
@lines = $file->lines( { chomp => 1 } );

ファイルにまとめて書き込み

# Path::Class
$file->spew( iomode => ':utf8', $data );

# Path::Tiny
$file->spew( { binmode => ':utf8' }, $data );

親ディレクトリ名でファイルを作成

# Path::Class
file($file->parent)->touch;

# Path::Tiny
$file->parent->touch;

ファイルをコピー

# Path::Class
$file->copy_to($path);

# Path::Tiny
$file->copy($path);

ファイルをリネーム

# Path::Class
$file->move_to($file_path);

# Path::Tiny
$file->move($file_path);

ファイルを指定ディレクトリに移動

Path::Tinyのmoveはrenameと同等の機能なので注意が必要。

# Path::Class
$file->move_to($dir_path);

# Path::Tiny
use File::Copy 'move';
move $file, $dir_path;

ディレクトリ配下のファイルを処理

# Path::Class
$dir->recurse( callback => sub {
    my $file = shift;
    return unless -f $file;
    print $file, "\n";
});

# Path::Tiny
my $iterator = $dir->iterator( { recurse => 1 } );
while( my $file = $iterator->() ) {
    next unless $file->is_file;
    print $file, "\n";
}