Bulknews::Subtech RSSフィード

2006/12/05 (火)

MobileAgent 07:34  MobileAgent - Bulknews::Subtech を含むブックマーク はてなブックマーク -  MobileAgent - Bulknews::Subtech

404 Blog Not Found:perl - 勝手に添削 - 条件分岐

よりおしゃれな方法として、HTTP::MobileAgentのサブクラスを作るという方法もあります。

おしゃれでもないし、そもそもこのコードでは動かない。

ここでnew()を以上のように定義しているのは、HTTP::MobileAgentのnew()の設計が少し特殊で、そのままでは継承可能となるように設計されていないからで

それには理由があって、USER_AGENT の文字列をみて適切なサブクラスに bless する Factory になっているから。そのインスタンスをもってきて自前のクラスに bless したら、動くわけがない。

use strict;
use warnings;

use HTTP::MobileAgent;
use Test::More 'no_plan';

{
    my $agent = HTTP::MobileAgent->new("DoCoMo/2.0 N2001");
    is $agent->is_docomo, 1;
    is $agent->is_foma, 1;
}

{
    package MyMobileAgent;
    use base 'HTTP::MobileAgent';
    sub new {
        my $class = shift;
        my $self = HTTP::MobileAgent->new(@_);
        bless $self, __PACKAGE__;
    }

    sub is_xhtml {
        my $self = shift;
        return 1 if $self->is_docomo and $self->is_foma;
        return 1 if $self->is_ezweb  and $self->is_win;
        if ($self->is_softbank){
            return 1 if $self->is_type_w or $self->is_type_3gc;
        }
        return 0;
    }
}

{
    my $agent = MyMobileAgent->new("DoCoMo/2.0 N2001");
    is $agent->is_docomo, 1;
    is $agent->is_xhtml, 1;
}

new() のところで HTTP::MobileAgent にきちんと @_ を渡すようにしておいた。これでも実行すると

% perl ~/tmp/mobileagent.t
ok 1
ok 2
not ok 3
#   Failed test at /home/miyagawa/tmp/mobileagent.t line 34.
#          got: '0'
#     expected: '1'
not ok 4
#   Failed test at /home/miyagawa/tmp/mobileagent.t line 35.
#          got: '0'
#     expected: '1'
1..4
# Looks like you failed 2 tests of 4.

となる。

継承をつかってきちんと動かしたければ、MyMobileAgent のサブクラスを動的につくって @ISA に DoCoMo を差し込むようにハックしなければダメ。無理やりかけばこうなるか。

package MyMobileAgent;

my $i;
sub new {
    my $class = shift;
    my $self = HTTP::MobileAgent->new(@_);
    my $pkg = __PACKAGE__ . "::". $i++;
    no strict 'refs';
    @{$pkg."::ISA"} = (ref $self, __PACKAGE__);
    bless $self, $pkg;
}

これで .t はとおるようになった。

そもそも後から機能追加するのに継承を使うというのはイケていない。すべての呼び出しを HTTP::MobileAgent から MyMobileAgent に変えなければならないし、is_xhtml 以外の機能をつけるときに拡張性がない。こういうのはメソッド追加するプラグインでやるのが定石。

package HTTP::MobileAgent::Plugin::XHTML;
use strict;

sub import {
    my $class = shift;
    *HTTP::MobileAgent::is_xhtml = sub { ... }
}

1;

これで、 use HTTP::MobileAgent::Plugin::XHTML; すれば大元のクラスにメソッドが追加できる。