HTML::MobileJP::Filter::DoCoMoGUIDで同一ホスト内でのguid=ONを有効にするには

今やってるやつでCatalyst::View::MobileJpFilterを使って実装しようと思ってるんだけどHTML::MobileJP::Filter::DoCoMoGUIDで下記のようなケースではguid=ONがついてくれないのです。

<a href="http://example.com/">link</a>

どうやらhttpから始まるURLに対してはつかないようですが、これは元となるHTML::StickyQueryモジュールのabsオプションを使えばついてくれるみたい。

my $html = '<a href="http://example.com/">link</a>';

my $sticky = HTML::StickyQuery::DoCoMoGUID->new;

local $sticky->{sticky}->{abs} = 1;

$sticky->sticky( scalarref => \$html ); # <a href="http://example.com/?guid=ON">link</a>

ただし、absオプションを使うと問答無用でguidが付いてしまいます。

外部のURLへリンクの場合にはguidが付いて欲しくないことが殆どだとおもうので、それに対応するためにHTML::MobileJP::Filter::DoCoMoGUIDOnHost(名前は適当)を考えてみました。

package HTML::MobileJp::Filter::DoCoMoGUIDOnHost;
use Moose;

with 'HTML::MobileJp::Filter::Role';

sub filter {
    my ($self, $html) = @_;
    
    unless ($self->mobile_agent->is_docomo) {
        return $html;
    }
    
    my $sticky = HTML::MobileJp::Filter::DoCoMoGUIDOnHost::_Private->new;
    local $sticky->{sticky}->{host} = $self->mobile_agent->get_header('host');
    $sticky->sticky( scalarref => \$html );
}

package HTML::MobileJp::Filter::DoCoMoGUIDOnHost::_Private;
use base qw/HTML::StickyQuery::DoCoMoGUID/;

sub sticky {
    my($self, %args) = @_;
    $args{param} ||= {};
    $args{param}->{guid} = 'ON' unless $args{disable_guid};

    local $self->{sticky}->{use_xhtml} = exists $args{xhtml} ? $args{xhtml} : 1;

    local *HTML::StickyQuery::DoCoMoGUID::_start = *HTML::StickyQuery::start;
    local *HTML::StickyQuery::start = *start;
    $self->{sticky}->sticky( %args );
}

sub start {
    my $self = shift;
    my($tagname, $attr, $attrseq, $orig) = @_;
    
    my $url = $attr->{href} || $attr->{action} || '';
    if ( $url =~ m{^https?://$self->{host}} ) {
        local $self->{abs} = 1;
        return $self->HTML::StickyQuery::DoCoMoGUID::start(@_);
    }
    
    $self->HTML::StickyQuery::DoCoMoGUID::start(@_);
}

1;

実装ですが、HTML::StickyQuery::DoCoMoGUIDが元々ハック的な実装方法で作られているため、さらにハックハックしちゃって混沌となってしまっています。

もはやここまできたらHTML::StickyQueryとHTML::StickyQuery::DoCoMoGUIDにhostオプションみたいなのを実装するほうが綺麗でしょうね。

# HTML::StickyQuery-v0.12

--- StickyQuery.pm      Wed Oct  8 18:46:55 2003
+++ _StickyQuery.pm     Mon Aug 18 15:11:34 2008
@@ -88,6 +88,12 @@
            $self->{output} .= $orig;
            return;
        }
+
+    if ($self->{host} && $u->host ne $self->{host} ) {
+           $self->{output} .= $orig;
+           return;
+    }
+
        # when URI has other scheme (ie. mailto ftp ..)
        if(defined($u->scheme) && $u->scheme !~ m/^https?/) {
            $self->{output} .= $orig;

で、HTML::StickyQuery::DoCoMoGUIDもHTML::StickyQueryに引数を渡せるように変更&hostオプションに対応して・・・

# HTML::StickyQuery::DoCoMoGUID-v0.01

--- DoCoMoGUID.pm       Tue Apr  8 21:39:12 2008
+++ _DoCoMoGUID.pm      Mon Aug 18 15:24:00 2008
@@ -9,7 +9,7 @@
 sub new {
     my $class = shift;
     bless {
-        sticky => HTML::StickyQuery->new( regexp => qr/./ ),
+        sticky => HTML::StickyQuery->new( regexp => qr/./, @_ ),
     }, $class;
 }

@@ -44,6 +44,11 @@
     if (!$self->{abs} && $u->scheme) {
         $self->{output} .= $orig;
         return;
+    }
+
+    if ($self->{host} && $u->host ne $self->{host} ) {
+           $self->{output} .= $orig;
+           return;
     }

     # when URI has other scheme (ie. mailto ftp ..)

で、さらにHTML::MobileJp::Filter::DoCoMoGUIDもHTML::StickyQuery::DoCoMoGUIDに引数を渡せるように変更すれば・・・

--- DoCoMoGUID.pm       Tue Jul  8 06:10:48 2008
+++ _DoCoMoGUID.pm      Mon Aug 18 15:20:05 2008
@@ -12,7 +12,10 @@
         return $html;
     }

-    HTML::StickyQuery::DoCoMoGUID->new->sticky( scalarref => \$html );
+    my $config = %{$self->config || {}};
+    $config->{host} = $self->mobile_agent->get_header('host') if $config->{host_auto};
+
+    HTML::StickyQuery::DoCoMoGUID->new(%$config)->sticky( scalarref => \$html );
 }

 1;

__END__

filters:
  module: DoCoMoGUID
  config:
    host_auto: 1

ってな感じで、いけそうです。

ちなみに上記3パッチのみ脳内実装なので動くかわかりません><

追記

id:tomi-ruさんからコメント頂きました。

なるほど、根本解決ではないものの、明らかにそっちの方が楽ですね^^;

Catalyst限定ですが、Catalyst::Plugin::SmartURIを使ってuri_forにて相対URLを返すことよって、そもそも絶対URLを使わないようにして上記の問題を切り抜けるという対策ですね。

とりあえず僕もコレ使います。

ありがとうございました!