Fixture系モジュールはコールバックで値を入れられる方がいい

 例えば日付に絡むテストをしたい時、ダミーデータとしてハードコードしてしまうと、後々、データが古いというだけでテストがコケるという可能性が出てくる。
 まあ、可能性というか、実際今僕のところで起きたんだけどさ。
 もうちょっと具体例を挙げると、週間ランキングのロジックをテストをしたいとかいうとき、ギリギリ3,4日後くらいまではなんとかなっても、もし1ヶ月先に何らかの事情でそのテストを回したいとき、そんなところで落ちてたら、無駄に原因究明の時間を使う事になる。
 ということで、DBIx::MoCo::Fixtureのload_fixtureをちょっと弄る。

{
    package DBIx::MoCo::Fixture;
    use Data::Visitor::Callback;

    our $Substitutions = {};

    sub append_substitutions {
        my ( $key, $callback ) = @_;
        $Substitutions->{$key} = $callback;
    }

    no warnings 'redefine';
    sub load_fixture {
        my $file = shift;
        my $yaml = $file->slurp or die $!;
        Data::Visitor::Callback->new(
            plain_value => sub {
                return unless defined $_;
                for my $sig ( keys %$Substitutions ) {
                    if(/__${sig}\((.+?)\)__/) {
                        return $Substitutions->{$sig}->($1);
                    }
                }
                return $_;
            }
        )->visit( YAML::Syck::Load($yaml) );
    }
}

DBIx::MoCo::Fixture::append_substitutions(
    add => sub {
        my $val = shift;
        require DBIx::MoCo::Column::DateTime;
        return DBIx::MoCo::Column::DateTime->DateTime_as_string(
            DateTime->now->set_time_zone('Asia/Tokyo')->add( eval "($val)" ) );
    }
);

 こんな風にしておくと、

---
created_on: __add(days => -3)__

 というのが

---
created_on: 2009-03-27 18:32:32

 となってくれる。てか、Catalyst::Plugin::ConfigLoaderでやってることそのまんまっすね><
 あ、あと、evalはご愛嬌ということでお願いします><
(追記)
 これ、たまたま僕が今使ってるO/R MapperがMoCoなので、MoCoのコード例として出しましたけど、Test::Fixture::DBIC::SchemaとかDBIx::Class::Fixtureとか、ダミーデータをハードコードさせるモジュール全てに言えることですので。