MVCその4
Model
Modelとは何でしょうか。Modelは、アプリケーションの中枢です。今回のプログラムは何(What)をするプログラムでしょうか。HTMLを表示する? JSONを出力する? いえ、それはHowであってWhatではありません。このプログラムの"What"は「動画を検索する」です。この「動画を検索する処理」を担当するのがModelに相当します。
WEB+DB PRESS Vol.44 P170
僕がアレンジしたので置き換えると、「はてなタグ検索する処理」がModelに当たるってことか。
Controller
Controllerはユーザが入力した生データを受け取る部分(コンポーネント)です。生データを受け取って、Modelに渡します。するとModelが検索処理を行います。
WEB+DB PRESS Vol.44 P170
というわけで
Modelを分離してみる。
一枚岩プログラムからViewを分離しました。そこから今度はModelを分離します。動画を検索するというドメインロジックを抽出してモジュール化するのです。インタフェースは何でもよいが、Modelは共通、ということを述べました。これを逆に考えると、Webアプリケーションと異なるインタフェース、たとえばCUIのコマンドラインスクリプトからも使えるようにモジュール化することができれば、そのモジュールはModelたり得るわけです。
なるほど。
lib/MyHatena/Tag.pm
package MyHatena::Tag; use strict; use warnings; use base qw/Class::Accessor::Fast/; our $VERSION = 0.01; use LWP::UserAgent; use Params::Validate qw/:all/; use URI; use XML::Simple; use Encode qw/encode/; use MyHatena::Tag::Result; __PACKAGE__->mk_accessors(qw/title link/); my $HATENA_TAG_API = "http://b.hatena.ne.jp/t/"; sub search { my $class = shift; my ($query) = validate_pos(@_, { type => SCALAR }); my $uri = URI->new($HATENA_TAG_API.$query); $uri->query_form( sort => 'eid', mode => 'rss' ); my $ua = LWP::UserAgent->new; $ua->agent(join('/', __PACKAGE__, __PACKAGE__->VERSION)); my $res = $ua->get($uri); return $res->status_line if $res->is_error; my @entries = $class->_parse_xml(\$res->content); return MyHatena::Tag::Result->new(\@entries); } sub _parse_xml { my $class = shift; my ($xml_ref) = validate_pos(@_, { type => SCALARREF }); my $parser = XML::Simple->new; my $xml; eval { $xml = $parser->XMLin($$xml_ref) }; die $@ if $@; my @entries; for my $entry (@{$xml->{item}}) { push @entries, $class->new({ title => encode('utf8', $entry->{title}), link => $entry->{link}, }); } return @entries; } 1; __END__
lib/MyHatena/Tag/Result.pm
package MyHatena::Tag::Result; use strict; use warnings; sub new { my $class = shift; my $self = shift || []; bless $self, $class; } sub entries { my $self = shift; return @$self; } 1; __END__
テスト
Modelを分離することができたので、プログラムのメインロジックである「検索処理」をテストすることができる。
もうなんていうか感動。
今まで関わってきたアプリケーション開発はこんなのなかったからなあ。
なのでまずは、検索処理だけするモジュールをロードしてちゃんと出力されるかチェック。
#!/usr/local/bin/perl # tag_search.pl use strict; use warnings; use feature qw/say/; #use lib qw/lib/; use FindBin::libs; use MyHatena::Tag; my $query = shift or die "usage: $0 <term>"; # MyHatena::Tag::Resultが返ってくる my $result = MyHatena::Tag->search($query) or die "Can't search by [$query]."; for my $entry ($result->entries) { say $entry->title; say $entry->link; } __END__
$ ./tag_search.pl Perl shuraba.com - Perl: 変数・定数 http://www.shuraba.com/?p=computing/perl/value Perl - スカラー変数 http://www.booran.com/menu/perl/scalar.html 配列の基礎 - Perl入門〜サンプルコードによるPerl入門〜 http://tinyurl.com/yz7y2yb ………
ok。