« Catalyst's ACCEPT_CONTEXT | メイン | Catalystのコンポーネントの読み込み »

Catalystのclassとinstance

CatalystをデバッグOnで起動したときに最初の方にでてくる

.-------------------------------------------------------------------+----------.
| Class                                                             | Type     |
+-------------------------------------------------------------------+----------+
| Traba::Model::DBISweet                                            | class    |
| Traba::Model::Trackbacks                                          | class    |
| Traba::Model::URLBL                                               | instance |
| Traba::View::RSS                                                  | instance |
| Traba::View::TT                                                   | instance |
'-------------------------------------------------------------------+----------'

これの右側のTypeがあるんだけど、この欄のclassかinstanceになるかは、Catalystの起動時のsetup_componentsで判定される。
判定に使われるのは、COMPONENTというクラスメソッド。ちなみに、上は暦トラバのもの。

Catalyst::Componentにはそれが実装されてる。中身的には、configをまとめてコンストラクタのnewを呼び出すというコード。

sub COMPONENT {
    my ( $self, $c ) = @_;
    # Temporary fix, some components does not pass context to constructor
    my $arguments = ( ref( $_[-1] ) eq 'HASH' ) ? $_[-1] : {};
    if ( my $new = $self->NEXT::COMPONENT( $c, $arguments ) ) {
        return $new;
    }
    else {
        if ( my $new = $self->new( $c, $arguments ) ) {
            return $new;
        }
        else {
            my $class = ref $self || $self;
            my $new = { %{ $self->config }, %{$arguments} };
            return bless $new, $class;
        }
    }
}

ということで、Catalyst::ComponentをベースとするModel/Viewは(おかしい事をしないかぎり)必ずinstanceになる。

上のリストにある、Traba::Model::URLBLはTrackbackスパムのチェックをするクラスで、id:miyagawaのKwiki::URLBLを参考にして、以下のような感じで実装されている。

package Traba::Model::URLBL;

use strict;
use warnings;
use base 'Catalyst::Model';
use NEXT;
use Net::DNS::Resolver;
use URI;

sub new {
    my($class, $c, $config) = @_;
    my $self = $class->NEXT::new($c,$config);
    $config->{urlbl_dns} ||= [qw/sc.surbl.org bsb.spamlookup.net rbl.bulkfeeds.jp/];
    $self->config($config);
    return $self;
}

sub is_blocked {
    my($self, $url) = @_;
    my $uri = URI->new($url);
    my $domain = $uri->host;
    $domain =~ s/^www\.//;
    my $res   = Net::DNS::Resolver->new;
    for my $dns (@{$self->config->{urlbl_dns}}){
	    my $q = $res->search("$domain.$dns");
        return 1 if $q && $q->answer;
    }
    return;
}
1;