おっと

http://b.hatena.ne.jp/miyagawa/20060515#bookmark-1935278

[plagger] これはそう思う、というかどのフェーズでも動けるプラグインは、実行フェーズを指定するオプションがあってもいいのかも

どのフェーズっちゅうことは、update/smartfeed/publishのキャズムをこえなあかんな。
さっきのだけじゃ物足りんわ。

ところでキャズムの使いかたはあってまっか?

たぶんこんなんや

Plagger.pmをこうすればええんや

sub run_hook {
    my($self, $hook, $args, $once) = @_;
    $hook =~ s/\.(pre|post)$//;
    my $hatena = $1;
    for my $action (@{ $self->{hooks}->{$hook} }) {
        my $plugin = $action->{plugin};
        if ($hatena && $hook =~ /(feed|entry)/) {
            my $jitensya = $plugin->conf->{jitensya};
            $jitensya = $1 eq 'entry' ? 'pre' : 'post' unless $jitensya;
            next unless $jitensya eq $hatena;
        }
        if ( $plugin->rule->dispatch($plugin, $hook, $args) ) {
            my $done = $action->{callback}->($plugin, $self, $args);
            return 1 if $once && $done;
        }
    }

    # if $once is set, here means not executed = fail                                                                                                                        
    return if $once;
}

そうすればPluginは書き変えなくてすむしワシの大好きな自転車も残る。しかもはてなまで出て来る。
ようは自転車とはてなの意見が食い違ったら動かなくなるわけや。

よう考えたら

    for my $feed ($self->update->feeds) {
        for my $entry ($feed->entries) {
            $self->run_hook('update.entry.fixup.pre', { feed => $feed, entry => $entry });
        }
        $self->run_hook('update.feed.fixup.pre', { feed => $feed });

        for my $entry ($feed->entries) {
            $self->run_hook('update.entry.fixup.post', { feed => $feed, entry => $entry });
        }
        $self->run_hook('update.feed.fixup.post', { feed => $feed });
    }

こんな実装にしといてユーザがconfig.yamlでこのフィルターはpreでーこのフィルターはpostのタイミングで動いてくれやー
と指定できた方がええんちゃう?
smartfeedとpublishでもおなしかんじでもええやな。

そなればOnAggregatorFinalizeがなくなって万々歳やわ。
jitensya入れられなくなって淋しいのは内緒や。

Filter::HatenaBookmarkUsersCountOnAggregatorFinalize

よう考えたら6usersのエントリだけ欲しいんやからHatenaBookmarkUsersCountの実行フェーズを先にほかせばよいんやった。
ほなら

  - module: Filter::HatenaKeywordTag
    rule:
      expression: $args->{entry}->{meta}->{hatenabookmark_users} eq 6

とか書けて、はてな万々歳ちゃうやろか?

しかしけったいな名前やなぁ

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

use XMLRPC::Lite;

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'aggregator.finalize' => \&jitensya,
    );
}

sub jitensya {
    my($self, $context, $args) = @_;
    for my $feed ($context->update->feeds) {
        $self->update($context, { feed => $feed });
    }
}

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

    my @permalink = map $_->permalink, $args->{feed}->entries;

    $context->log(info => 'Requesting XMLRPC call to Hatena Bookmark with ' . scalar(@permalink) . ' link(s)');

    my $map = XMLRPC::Lite
        ->proxy('http://b.hatena.ne.jp/xmlrpc')
        ->call('bookmark.getCount', @permalink)
        ->result;

    unless ($map) {
        $context->log(warn => 'Hatena Bookmark XMLRPC failed');
        return;
    }

    $context->log(info => 'XMLRPC request success.');

    for my $entry ($args->{feed}->entries) {
        if (defined(my $count = $map->{$entry->permalink})) {
            $entry->meta->{hatenabookmark_users} = $count;
        }
    }
}

1;

CacheOnAggregatorFinalize

一度見たエントリを何度もチェックするのだるいわ。
Cacheだとなんか知らへんけどEntryFullTextが全部動きよるし。

package Plagger::Plugin::CacheOnAggregatorFinalize;
use strict;
use base qw( Plagger::Plugin );
    
use DB_File;
use Digest::MD5;

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self, 
        'aggregator.finalize' => \&strip,
    );

    unless ($self->conf->{file}) {
        $context->error("please file config");
        return;
    }
    
    my %cache;
    my $a = tie %cache, 'DB_File', $self->conf->{file};
    $self->{__cache} = \%cache;
}   

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

    for my $feed ($context->update->feeds) {
        $self->update($context, { feed => $feed });
    }
    $self->fixup($context);
}

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

    return unless $self->{__cache};

    my @entries;
    my $feed = $args->{feed};
    for my $entry ($feed->entries) {
        my $key = $feed->id . '-' . $entry->id_safe;

        $key .= $self->check_key('author', $entry->author);
        $key .= $self->check_key('title', $entry->title);

        my $text = $entry->text;
        utf8::encode($text) if utf8::is_utf8($text);
        my $value = !$self->conf->{diff_mode} || Digest::MD5::md5_hex($text);
        if ($self->{__cache}->{$key}) {
            next unless $self->conf->{diff_mode};
            next if $self->{__cache}->{$key} eq $value;
        }
        print "cache: $key $value\n";
        $self->{__cache}->{$key} = $value;
        push(@entries, $entry);
    }
    $feed->{entries} = \@entries;
}

sub check_key {
    my($self, $flag, $str) = @_;
    utf8::encode($str) if utf8::is_utf8($str); 
    return '-' . Digest::MD5::md5_hex($str) if $self->conf->{$flag} && $str;
    return '';
}

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

    return unless $self->{__cache};
    untie %{ $self->{__cache} };

    my $update = $context->update;
    $context->update( Plagger::Update->new );
    for my $feed ($update->feeds) {
        $context->update->add($feed) if @{ $feed->entries };
    }
}

1;

hook

# miyagawa 『>Plaggerはregister_hookで宣言されたhookの先頭のみをruleで見るのでregister_hookの順番には気を使うべき。
ま、それでもいいんですが、
sub rule_hook { ’publish.entry.fixup’ }
とするほうがよりexplicitで正しいです。』

そんなグレイトな方法が!

Filter::StripTags

一度tagsをクリアーしてしまおう!

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

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

sub update {
    my($self, $context, $args) = @_;
    $args->{entry}->tags([]);
}

1;

__END__

=head1 NAME

Plagger::Plugin::Filter::StripRSSAd - Strip Tags to Entry

=head1 SYNOPSIS

  - module: Filter::StripTags

=head1 DESCRIPTION

=head1 AUTHOR

id:j708

=head1 SEE ALSO

L<Plagger>

=cut