Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

MVCその3

続き。

Viewを分離する

その前にJSON出力をサンプルではしているけれど、愛で割ります。
というわけで、きっちり一枚岩のはてブタグ(最新エントリ)検索ができたので、次のSTEPへ。
MVC渾然一体となったプログラムを分割していく。
まずはView!
これなら分かるし、知ってるし、使ったことがある!
と思ってるけどここは焦らず写経っぽく。
じゃあまずはTemplateで使う用のHTMLをば。

index.html
<html>
<head>
 <title>Hatena Tag Search</title>
</head>
<body>
 <h1>Hatena Tag Search</h1>
 <form method="get">
  <input type="text" name="search_tag" />
  <input type="submit" value="Search" />
 </form>
</body>
</html>
result.html
<html>
<head>
 <title>Hatena Tag Search - Result</title>
</head>
<body>
 <h1>Hatena Tag Search</h1>
 <form method="get">
  <input type="text" name="search_tag" value="[% search_tag | html %]" />
  <input type="submit" value="Search" />
 </form>
 <h2>Result ([% result.size %])</h2>
 <ul>
  [% FOREACH entry IN result -%]
  <li><a href="[% entry.link %]">[% encode(entry.title) | html %]</a></li>
  [% END -%]
 </ul>
</body>
</html>

覚えたこと。
resultは配列リファレンス。
[% -%]にすると改行が減らせる。

html とか uri とかはフィルタで、いい感じにHTMLしてくれる。


で、問題のViewを切り離したcgi。

tag_search3.cgi
#!/usr/local/bin/perl
# tag_search3.cgi
use strict;
use warnings;
use CGI qw/:standard/;
use LWP::UserAgent;
use Params::Validate qw/:all/;
use URI;
use XML::Simple;
use Encode qw/encode/;
use Template;

my $HATENA_TAG_API = "http://b.hatena.ne.jp/t/";

my $q = CGI->new;

print header( -type => 'text/html', -charset => 'utf-8' );

# Which Template ?
my $tmpl = $q->param('search_tag')
  ? '/Users/rightgo09/Script/Perl/template/result.html'
  : '/Users/rightgo09/Script/Perl/template/index.html'
  ;

# Substitution Data
my $vars = $q->param('search_tag')
  ? { result => search_hatena_tag($q->param('search_tag'))->{item},
      encode => sub { encode('utf8', +shift) },
      search_tag => $q->param('search_tag') }
  : {}
  ;

# Rendering TT
my $template = Template->new(ABSOLUTE => 1);
$template->process($tmpl, $vars, \my $out)
  or die $template->error;

print $out;

sub search_hatena_tag {
  my ($query) = validate_pos(@_, { type => SCALAR });

  # Hatena Tag RSS API
  my $uri = URI->new($HATENA_TAG_API.$query);

  $uri->query_form( sort => 'eid', mode => 'rss' );

  my $ua = LWP::UserAgent->new;

  my $res = $ua->get($uri);
  die $res->status_line if $res->is_error;

  return _parse_data(\$res->content);
}

sub _parse_data {
  my ($xml_ref) = validate_pos(@_, { type => SCALARREF });
  my $parser = XML::Simple->new;
  my $data;
  eval { $data = $parser->XMLin($$xml_ref) };
  die $@ if $@;
  return $data;
}
__END__

下半分くらいは前と一緒。
だけど、やっぱりHTMLを直接出していないだけ、すっきり見える。
ただその分置き換え用のデータをごちゃごちゃしなくちゃいけなくて、まだまだその辺は堅苦しい。
覚えたこと。
テンプレートに絶対パスを渡すならTemplate->newでABSOLUTE=>1が要る。