hinetmaniaコード修正

http://d.hatena.ne.jp/lestrrat/20070524#1179968337でほめてもらえた!ので,気を良くしてコードをさらに修正,動かし始めました.設定部分はconfig.ymlとして切り出し,アプリケーション固有の部分を分離しています.

スクリプト

Gungho周りのスクリプトはこんな感じになりました.条件分けするhost名とかpath名とかで予めインタフェースを用意しておくとさらに美しくなるかな?host名をハードコードしてるのがちょっと美しくないです.Facade使ったらってコメントに気づくのが遅かったので,それはまた後でやります.

#!/usr/local/bin/perl

use strict;
use warnings;
use FileHandle;
use Gungho::Inline;
use QuakeInfo;

Gungho::Inline->run(
    'config.yml',
    {
        provider => \&provider,
        handler  => \&handler,
    }
);

sub provider {
    my ( $p, $c ) = @_;

    $p->add_request( $c->prepare_request( QuakeInfo->Say() ) );
    1;
}

sub handler {
    my ( $h, $c, $req, $res ) = @_;

    return 1 if ( !$res->is_success );

    my $code = {
        'www.hinet.bosai.go.jp' => sub {
            QuakeInfo->Compare($res);
        },
        'twitter.com' => sub {
            QuakeInfo->Check();
        },
    }->{ URI->new( $req->uri )->host };
    $code->();
    1;
}

上のスクリプトが呼び出しているアプリケーション固有の部分をQuakeInfoというモジュールにしてまとめてみました.

package QuakeInfo;
use strict;
use warnings;
use base qw(Class::Data::Inheritable);
use Gungho::Request;
use utf8;
use URI;
use Web::Scraper;
use Encode qw(find_encoding _utf8_off);

QuakeInfo->mk_classdata('Data');
QuakeInfo->mk_classdata( State => 0 );
QuakeInfo->mk_classdata(
    Scraper => scraper {
        process 'td.bgltsub+td.bgwhite', 'descr[]' => 'text';
        result 'descr';
    }
);

sub Compare {
    my ( $class, $res ) = @_;
    my $content_type = $res->headers->header('Content-Type');
    my $enc          = find_encoding($1)
      if ( $content_type =~ /charset=([A-Za-z0-9_\-]+)/io );
    my $html = $enc->decode( $res->content );
    my $new  = $class->Scraper->scrape($html);
    my $old  = $class->Data();

    $$new[2] =~ s/N//;
    $$new[3] =~ s/E//;

    if ( ( !$old ) || ( $$old[1] ne $$new[1] ) ) {
        $class->Data($new);
        $class->State(1);
    }
    return;
}

sub Check {
    my ($class) = shift;
    $class->State(0);
}

sub Say {
    my ($class) = shift;
    my $word = [
        sub {
            return Gungho::Request->new(
                GET => 'http://www.hinet.bosai.go.jp' );
        },
        sub {
            $class->State(2);
            my $data = $class->Data();
            my $text = sprintf
              "%sにM%sの地震が%sで発生しました %sq=%s%%20%s",
              $$data[1], $$data[5], $$data[0],
              'http://maps.google.co.jp/maps?f=q&hl=ja&t=k&om=0&z=7&',
              $$data[2], $$data[3];
            _utf8_off($text);

            my $uri = URI->new('http:');
            $uri->query_form( status => $text );
            return Gungho::Request->new(
                POST => 'http://twitter.com/statuses/update.json',
                [ 'Content-Type', 'application/x-www-form-urlencoded' ],
                $uri->query,
            );
        },
        sub {
            return Gungho::Request->new(
                GET => 'http://www.hinet.bosai.go.jp' );
        },
    ]->[ $class->State() ];
    return $word->();
}

Gunghoスクリプトが呼び出す設定ファイルはこんな感じになります.

---
components:
  - Throttle::Domain
  - Authentication::Basic
credentials:
  basic:
    -
      - http://twitter.com:80
      - Twitter API
      - username
      - password
throttle:
  domain:
    domains:
      - match: \.bosai\.go\.jp$
    interval: 300
    max_items: 10