Filter::Rule と Filter::CloneFeed

最近は Plagger いじりの記録と化してるこのブログですが、今日もまた Plagger ネタですよ。

ちょっとやりたいことがあって、Filter::Rule の改造と、Filter::CloneFeed というものを作ってみました。やりたいことが何かというのは長くなるので、後回しにして、まずは Filter::Rule の修正内容と、Filter::CloneFeed の説明を。

Filter::Rule の修正内容はこんな感じです。

Index: plagger/trunk/lib/Plagger/Plugin/Filter/Rule.pm
===================================================================
--- plagger/trunk/lib/Plagger/Plugin/Filter/Rule.pm (revision 258)
+++ plagger/trunk/lib/Plagger/Plugin/Filter/Rule.pm (revision 259)
@@ -19,4 +19,12 @@
 sub feed {
     my($self, $context, $args) = @_;
+
+    if ( defined ( my $expression = $self->conf->{expression} ) ){
+        my $status = eval $expression;
+        if ($@) {
+            Plagger->context->log(error => "Expression error: $@ with '$expression'");
+        }
+        return unless $status;
+    }
 
     for my $entry ($args->{feed}->entries) {

これにより何ができるかというと、以下のような yaml を書くことで、フィルタを適用するためのルールを設定することができます。

  - module: Filter::Rule
    rule:
      module: Fresh
      duration: 60
    config:
      expression: $args->{feed}->type eq 'AmazonWebService'

この例だと、feed type が AmazonWebService であるフィードには Rule::Fresh を適用する、それ以外のフィードには何もフィルタをかけずにそのままにする、という動作になります。

次に Filter::CloneFeed ですが、名前の通りフィードの複製をつくります。で、複製されたフィードは type が clone となります。ソースはこれだけです。

package Plagger::Plugin::Filter::CloneFeed;
use strict;
use base qw( Plagger::Plugin );

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'update.feed.fixup' => \&clone,
    );
}

sub clone {
    my($self, $context, $args) = @_;

    my $feed = $args->{feed}->clone;
    $feed->type('clone');
    $context->update->add($feed);
}

1;

で、これで何がやりたかったかというと、以下のようなことがやりたかったんです。

  - module: CustomFeed::AmazonWebService
    config:
      title: Amazon - New Books
      developer_token: XXXXXXXXXXXXXXXXXXXX
      associate_id: xxxxxx-22
      keywords:
        - 川原正敏

  - module: Filter::CloneFeed

  - module: Filter::Rule
    rule:
      module: Ahead
    config:
      expression: $args->{feed}->type eq 'clone'

  - module: Publish::iCal 
    config:
      dir: /home/miya/ical
      filename: %t.ics
    rule:
      module: FeedType
      type: AmazonWebService

  - module: Publish::Gmail
    config:
      mailto:   xxx@gmail.com
      mailfrom: xxx@mizzy.org
      mailroute:
        via: smtp
        host: localhost
    rule:
      module: FeedType
      type: clone

言葉で説明すると、こんな感じです。

要するに、同じフィードでも、Publish プラグイン毎に異なる内容で Publish したかった、というわです。

最初は以下のような yaml で、Publish::iCal では Rule を指定せずに全部吐き出す、Publish::Gmail では Rule::Ahead を適用して、1日以内に発売される商品情報だけ送信、とできるんじゃないかな、と思ったのですが、Publish::Gmail は publish.feed フックで動作していて、Rule でエントリレベルのフィルタリングができないんですよね。

  - module: CustomFeed::AmazonWebService
    config:
      title: Amazon - New Books
      developer_token: XXXXXXXXXXXXXXXXXXXX
      associate_id: xxxxxx-22
      keywords:
        - 川原正敏

  - module: Publish::iCal 
    config:
      dir: /home/miya/ical
      filename: %t.ics

  - module: Publish::Gmail
    config:
      mailto:   xxx@gmail.com
      mailfrom: xxx@mizzy.org
      mailroute:
        via: smtp
        host: localhost
    rule:
      module: Ahead

こういった事情で、Filter::Rule を改造し Filter::CloneFeed をつくってみました。もっとエレガントな方法があれば教えてください。

追記
もっとエレガントな方法教えてもらいました。というか、上でやったことは全くの無駄でした。なので参考にしないでください。