Catalystで日付オブジェクトを扱う

Catalyst::Plugin::DateTimeを使えば$c->datetimeでDateTimeオブジェクトが取得できます。

またCatalyst::Plugin::DateTimeから派生したCatalyst::Plugin::DateTime::Constructorを使えばもう少し色々機能が追加されます。

ま基本的にはこれらのプラグインを使って日付を扱えばいいんだけども独自の機能を追加した日付オブジェクトを扱えないので困ったさんです。

でですね。どーせならこの間自分で作ったコンポーネント型日付クラスのDate::ClassをCatalystから扱えるようにプラグインにしてみました。

Date::Classに関しては下記記事を参照ください。

コンポーネント追加の処理をyamlで定義できると面白いと思ったのでそれで実装してみました。。

package Catalyst::Plugin::Date::Class;
use strict;
use warnings;

use UNIVERSAL::require;
use Class::Inspector;
use Carp qw/croak/;

our $VERSION = '0.01';
our $DT_CLASS;

sub setup {
    my $c = shift;
    $c->NEXT::setup(@_);
    
    my $config = $c->config->{dateclass} || {};
    
    my $dt_class = $config->{base_name} ||= "${c}::Date::Class";
    
    if ( Class::Inspector->installed($dt_class) ) {
        $dt_class->require
            or croak "can't load date class '$dt_class': $@";
    }
    else {
        eval qq{
            package $dt_class;
            use strict;
            use warnings;
            use base qw/Date::Class/;
        };
        croak $@ if $@;
    }
    
    my @comps = @{$config->{components}};
    
    if ( $config->{default_time_zone} ) {
        unshift @comps, 'DefaultTimeZone';
    }
    
    $dt_class->load_components( @comps );
    for my $comp ( @comps ) {
        $c->log->debug("$config->{base_name} $comp loaded.");
    }
    
    if ( $config->{default_time_zone} ) {
        $dt_class->default_time_zone($config->{default_time_zone});
    }
    
    $DT_CLASS = $dt_class;
}

sub datetime {
    my $c = shift;
    
    return @_ ? $DT_CLASS->new(@_)
              : $DT_CLASS->now;

}

# alias
*dt = \&datetime;

1;

でmyapp.yamlには下記のように定義する

name: MyApp
dateclass:
  base_name: MyApp::Date::Class
  default_time_zone: Asia/Tokyo
  components:
    - Iterator
    - MonthList
    - DiffCount
    - Core

base_nameで設定されているモジュール名を基準にしてcomponentsで設定されているコンポーネントを追加する。

でbase_nameのモジュールが存在しない場合はevalで定義する、存在してる場合はそれをrequireする。

あとは$c->datetimeでオブジェクトを取得できるようになるって感じです。

コレ、自分で作っといてなんですが、何気に使いやすいのでためしに今回の仕事で使うことにしました。

ソースコード欲しい人いるかはわかんないけど一応下記に置いときます。

ちなみにテストコードはあまりありませんorz