2009/02/17

モダンPerl入門 デザインパターン実装の練習 -Iterator-

モダンPerl入門の2章では、各種デザインパターンをPerlで実装した例が出ています。
あまりデザインパターンが得意ではないので、頭の整理と練習がてら自分で書いてみたいと思います。
今日はIterator。

Iteratorは何かデータを順番に取り出していく処理を抽象化するためのパターンです。
何かのデータとは、配列であったりファイルであったり、データベースであったりという感じです。

何かの連続したデータをひとつずつ取り出すときはIteratorを使った方が良さそうということなようです。
例えば、従来は配列で持っていたデータをある日ファイルに持つようになりましたと。
そんなとき、Iteratorを使っていない場合は該当箇所をすべて直す必要があります。
しかし、Iteratorを使っていればデータを取り出すという処理が抽象化されているので、使用するオブジェクトを変更するだけで良いのです。
よかったね、よかったね、ということになると。
# あってるか不安…


書籍の例では配列とリンクリスト(Data::LinkedListという仮想のモジュールを使用)、ファイル用のIteratorを実装していました。
ひとまず、軽く実践できそうな配列とファイル(File::IOを使用)の実装をしてみました。

package MyIterator;
use Moose::Role;

requires qw(next);

no Moose::Role;

package MyIterator::Array;
use Moose;
use MooseX::AttributeHelpers;

with 'MyIterator';

has 'array' => (
metaclass => 'Collection::Array',
is => 'rw',
isa => 'ArrayRef',
required => '1',
trigger => sub {
my ($self, $list) = @_;
$self->size(scalar @$list);
},
provides => {
get => 'array_get'
},
);

has 'size' => (
is => 'rw',
isa => 'Int',
default => 0,
);

has 'current' => (
metaclass => 'Number',
is => 'rw',
isa => 'Int',
default => 0,
provides => {
add => 'current_add'
}
);

__PACKAGE__->meta->make_immutable;

no Moose;

sub next {
my $self = shift;
if ($self->current >= $self->size){
return ();
}

my $i = $self->current;
$self->current_add(1);
return $self->array_get($i);
}

1;

package MyIterator::File;
use Moose;

with 'MyIterator';

has 'filepath' => (
is => 'rw',
isa => 'Str',
required => 1,
);

has 'fh' => (
is => 'rw',
);

__PACKAGE__->meta->make_immutable;

no Moose;

use IO::File;

sub BUILD {
my $self = shift;

my $io = IO::File->new();
$io->open($self->filepath(), 'r') or die $!;
$self->fh($io);

return $self;
}

sub DESTROY{
my $self = shift;
$self->fh()->close()
}

sub next {
my $self = shift;

my $fh = $self->fh();
my $line = <$fh>;

return $line ? $line : ();
}

1;

package main;

my $iterator = MyIterator::Array->new(array => ['a', 'b', 'c']);
while (my $result = $iterator->next()) {
chomp $result;
print "$result\n";
}

$iterator = MyIterator::File->new(filepath => '/Users/hiroki/Documents/perl/iterator.pl');
while (my $result = $iterator->next()) {
chomp $result;
print "$result\n";
}


MyIteratorが今回作成するIteratorのインターフェイス。
インターフェイスはMoose::Roleを使うと簡単に実現できます。
今回はnextメソッドを必ず実装するようにしました。

MyIterator::Arrayが配列用のIterator。
データが入った配列を格納するarray、配列のサイズを格納するsize、読み込み中の現在の位置を表すcurrentのプロパティがあります。
arrayプロパティのtriggerで1回だけsizeの初期化を行うようになっています。
あとはnextメソッドが実装されています。
なるほどー、MooseとMooseX::AttributeHelpersを使うとこんなに便利なのか。

MyIterator::Fileがファイル用のIterator。
これは自分で書いた。
まず、ファイルハンドルの初期化をBUILDメソッドで行いました。
BUILDメソッドはコンストラクタで初期化された後に呼び出されるので、プロパティなどに値が入っているのは保証されています(required => 1にした場合)。
あとはnextメソッドを実装しました。
returnのところが三項演算子を使っていてちょっとトリッキーですね(これは本に書いてあった)。

で、package main以降が実際に走るコード。
最初は引数で渡した配列を順に表示してる処理です。
次が、ファイルから1行ずつ読み込んで表示する処理です。
どちらもオブジェクト作成の方法は違いますが、値を取り出す処理は一緒です。
なので、$iteratorにはMyIteratorを実装したものが入っていれば同じ処理で値が取り出せます。

次回以降はまた違うデザインパターンを実装してみます。

2009/02/15

MacPortsでMooseをインストール

昨日頼んでいた「モダンPerl入門」が届いたので早速読み進めてみました。
目次を読んだだけでも、最近のPerl関連の書籍にはないような内容が満載。
最近Catalystのことをネットで探しても若干古い情報しかなかったし…。
2章のPerlでデザパタの実装例を紹介しているのは、デザパタの理解が明らかに足りない私にとってはとてもうれしい。
とりあえず、1章と3章と4章を読んでみた。

1章でMooseが紹介されてますね。
名前だけは知ってたんですが、特に放置しててどのようなものかはわからなくて…orz
だいぶ前に流行が過ぎてて今更感はあるかもしれないですが、とりあえず使ってみることにしました。

そこでMacPortsにあったのでインストールしてみたのですが、ちょっと一筋縄ではいかなかったです。
きちんと記録をとってなかったのでちゃんと書けないのですが、ひとまずやったことは次のようなことです。
  • Perlを5.8.8から5.8.9に
  • p5-scalar-list-utilsを強制インストール


最初にはまったのはp5-test-simpleでなぜかエラーが出て先に進みませんでした。
私の環境ではPerl5.8が5.8.8_3がactiveになっていたので5.8.9_2に変更したところp5-test-simpleがインストールできました。


$ port installed | grep perl
perl5.8 @5.8.8_3+darwin_9 (active)
perl5.8 @5.8.9_2
$ sudo port deactivate perl5.8
---> Deactivating perl5.8
$ sudo port install perl5.8
---> Activating perl5.8 @5.8.9_2
---> Cleaning perl5.8
$ port installed | grep perl
perl5.8 @5.8.8_3+darwin_9
perl5.8 @5.8.9_2 (active)
$ sudo port install p5-test-simple
---> Activating p5-test-simple @0.86_0
---> Cleaning p5-test-simple


次にp5-scalar-list-utilsのインストールでなぜかこけました。
deactivateしてactivateしてみてもどうにもならなかったので-fオプションをつけて強制インストールしてしまいました。
どうやらwarningが出ているようですが、already existsということだけみたいでした。

sudo port -f install p5-scalar-list-utils
---> Installing p5-scalar-list-utils @1.19_1
---> Activating p5-scalar-list-utils @1.19_1
Warning: File /opt/local/lib/perl5/5.8.9/darwin-2level/auto/List/Util/Util.bs already exists. Moving to: /opt/local/lib/perl5/5.8.9/darwin-2level/auto/List/Util/Util.bs.mp_1234672795.
Warning: File /opt/local/lib/perl5/5.8.9/darwin-2level/auto/List/Util/Util.bundle already exists. Moving to: /opt/local/lib/perl5/5.8.9/darwin-2level/auto/List/Util/Util.bundle.mp_1234672795.
Warning: File /opt/local/lib/perl5/5.8.9/darwin-2level/List/Util.pm already exists. Moving to: /opt/local/lib/perl5/5.8.9/darwin-2level/List/Util.pm.mp_1234672795.
Warning: File /opt/local/lib/perl5/5.8.9/darwin-2level/Scalar/Util.pm already exists. Moving to: /opt/local/lib/perl5/5.8.9/darwin-2level/Scalar/Util.pm.mp_1234672795.
Warning: File /opt/local/share/man/man3/List::Util.3pm.gz already exists. Moving to: /opt/local/share/man/man3/List::Util.3pm.gz.mp_1234672795.
Warning: File /opt/local/share/man/man3/Scalar::Util.3pm.gz already exists. Moving to: /opt/local/share/man/man3/Scalar::Util.3pm.gz.mp_1234672795.
---> Cleaning p5-scalar-list-utils


これであとはsudo port install p5-mooseすれば無事インストールできます。
インストールだけでも少し時間がかかってしまいました。

いつも思うのですが、このブログは環境構築ものの記事ばっかりでその先がないですね…
反省ですね。

2009/02/11

Dropboxをインストール

各所で便利だと噂のDropboxを自宅のMacBookにインストールしてみました。
http://www.getdropbox.com/

クライアント用のソフトはMac以外にもLinux、Windows用のもあるようです。
最初にクライアントソフトで新しいアカウントを作成します。
それだけでインストールは完了です。

あとはFinderの場所→Dropboxを開けば使うことができます。
まだ使い方がよくわかってないです。

大きめのファイルを置いてもすぐに反映されるのはなぜだろう。
あとはバージョン管理みたいのも勝手にやってくれるんだよね?
あとで調べてまとめます。

sudoでパスワードを再度聞かれるまでの時間を調整する

前の記事でsudoコマンドでパスワードを再度聞かれるまで短いということを書きました。
調べたらやはりすぐ出てきました。ということで自分のMacBookにも反映させておきました。
ちなみに180(3時間)にしました。

Defaults timestamp_timeout = 180

私の場合は長くすれば便利だなーとか適当な考えでのばしたわけですが、時間をのばすと席を外している間にsudoで何か操作されてしまうというセキュリティ的な脅威も生みます。
なので、業務で使用する際はあまり長くするのも望ましくないかもしれないですね。

mod_access_tokenを使ってみた

livedoor labsで公開されたmod_access_tokenを使ってみました。
mod_access_tokenはコンテンツに対して有効期限をつけたりすることができるApacheモジュールです。
ソースはGoogle CodeにてMITライセンスで公開されています。
http://code.google.com/p/modaccesstoken/

とりあえず使い道はないけれどもインストールしてみました。
まず、ソースをダウンロード&展開して例のごとくインストールをします。
今回はMacPortsでインストールしたAapcheを使いたかったのでconfigureオプションにprefixとapxsのパスを指定しました。

$ tar xzvf mod_access_token-0.10.tar.gz
$ cd mod_access_token
$ ./configure --prefix=/opt/local/apache2 --with-apxs=/opt/local/apache2/bin/apxs
$ make
$ sudo make install

これでインストールは完了です。

ソースファイルのeg以下にhttpd.confの設定例とURLを生成するためのサンプルコード(Perl)が同梱されています。
今回は例としてhttp://localhost/hoge/index.htmlに対して有効期限の設定をしてみたいと思います。

まず、httpd.conf(/opt/local/apache2/conf/httpd.conf)に下記を追記します。
<Location /hoge>
AccessTokenCheck On
AccessTokenSecret 15cfb576a8bdc1551219fdeb3117ed85
AccessTokenAccessKey 7864ffcb01fb5cde1f1c2f37b619fbcd
</Location>

AccessTokenSecretとAccessTokenAccessKeyはサンプルのままです。
運用する際は変更しましょう。

これでApacheを/opt/local/apache2/bin/apachectl restartで再起動すれば/hoge以下のコンテンツはmod_access_tokenの管理下になるので、普通にアクセスすると403(Forbidden)が返ります。

次にURLを生成します。
URLは以下のようなものです。
http://localhost/hoge/index.html?Signature=<Signature>&AccessKey=<AccessKey>&Expires=<Expires>

AccessKeyはhttpd.confに設定したAccessKeyです。
Expiresは有効期限のUNIXタイムスタンプです。ということは有効期限は秒単位で設定できるんですね。
Signatureは"HTTPメソッド + URIのパス + 有効期限 + AccessKey"とAccessTokenSecretをHMAC-SHA1の値をBase64エンコードしたものです。

AccessKeyhttpd.confに設定したAccessKey
Signature"HTTPメソッド + URIのパス + 有効期限 + AccessKey"とAccessTokenSecretをHMAC-SHA1の値をBase64エンコードしたもの
Expires有効期限のUNIXタイムスタンプ

ちなみにeg以下にあるsign.plでURLを生成できます。
下記ではhttp://localhost/hoge/index.htmlに120秒の期限付きで生成する例です。
$ ./sign.pl http://localhost/hoge/index.html 7864ffcb01fb5cde1f1c2f37b619fbcd 15cfb576a8bdc1551219fdeb3117ed85 120

生成したURLでアクセスしてみるときちんとコンテンツが表示されると思います。
120秒後にアクセスすると再び403になります。

想定される使い方はURLを生成するアプリを作成して、アクセスさせるんだと思います。
livedoorの何かのサービスで使われているらしいです。

せっかくなので、mod_access_tokenのソースを読みつつApacheモジュールの勉強もしてみようかと思います。

2009/02/10

MacPortsのApacheを利用する

前回更新からだいぶ間があいてしまいました。

Leopardには最初からApache2.2が付属しています。
なので、Apacheを使いたければ付属のものを使えば良いのですが、なんとなく元々あるものはこのままにしておきたいと思ったので、MacPortsからApacheをインストールすることにしました。

$ sudo port install apache2

ちなみに今さら使わないかもしれないですが、Apache2.0系(apache20)、Apache1.3系(apache)もMacPortsからインストールできる模様です。

これで/opt/local/apache2以下にインストールされます。
起動する前に付属のApacheを停止します。
起動していなければこのまま先に進みます。

$ sudo apachectl stop

特に何も出力されないのですが、ブラウザからlocalhostにアクセスしてみて何も表示され泣けば付属のApacheはたぶん落ちてます。
# わかりにくいですね…

最後にMacPortsでインストールしたApacheを起動します。
一応psコマンドを使って起動しているかも確認します。

$sudo /opt/local/apache2/bin/apachectl start
$ ps axu|grep httpd
hiroki 25352 0.5 0.0 599780 460 s001 R+ 1:46AM 0:00.00 grep httpd
_www 25348 0.0 0.0 606772 624 ?? S 1:45AM 0:00.00 /opt/local/apache2/bin/httpd -k start
_www 25347 0.0 0.0 606772 624 ?? S 1:45AM 0:00.00 /opt/local/apache2/bin/httpd -k start
_www 25346 0.0 0.0 606772 624 ?? S 1:45AM 0:00.00 /opt/local/apache2/bin/httpd -k start
_www 25345 0.0 0.0 606772 624 ?? S 1:45AM 0:00.00 /opt/local/apache2/bin/httpd -k start
_www 25344 0.0 0.0 606772 624 ?? S 1:45AM 0:00.00 /opt/local/apache2/bin/httpd -k start
root 25343 0.0 0.1 606772 2228 ?? Ss 1:45AM 0:00.15 /opt/local/apache2/bin/httpd -k start

ひとまずこれであとは普通のApacheと同様に使用できます。
ちなみに設定ファイルは/opt/local/apache2/conf以下に、デフォルトのドキュメントルートは/opt/local/apache2/htdocsです。
ようは/opt/local/apache2以下に全部まとまってます。

ひとまず、htdocs以下にsudoしなくてもファイルが作成できるようにパーミッションを変更しておきます。

$ chmod 777 /opt/local/apache2/htdocs

これからはこのApacheを使っていろいろしたいと思います。

というかportsするたびにsudoしなきゃいけないのがだんだん面倒になってきました。
しかもsudoは連続して使えばパスワードが毎回聞かれることはないのですが、一定時間空けるとパスワード聞かれます。
2、3時間はパスワードなしで作業したいです。
この辺も設定できそうなので近いうちに調べてみます、というかぐぐればすぐ出てきそう…。