データをイテレーションしながらオブジェクト化
したくなったのでMooseでもよかったのですが
これまたでっちあげてみた。
package Data::Object; use strict; use warnings; our $VERSION = '0.01'; use Data::Object::Iterator; sub new { my ($class, $args) = @_; my $itr = Data::Object::Iterator->new($args); return $itr; } 1; package Data::Object::Class; use strict; use warnings; use Sub::Install qw/install_sub/; sub new { my ($class, $data) = @_; my $self = bless $data, $class; $self->init; return $self; } sub init { my $self = shift; for my $field (keys %{$self->{data}} ) { next if $self->can($field); install_sub({ as => $field, code => $self->_razy_inflate_data($field), }); } } sub _razy_inflate_data { my ($self, $field) = @_; return sub { my $self = shift; if ( $self->{hooks}->{$field} ) { $self->{hooks}->{$field}->($self->{data}->{$field}); } else { $self->{data}->{$field}; } }; } 1; package Data::Object::Iterator; use strict; use warnings; use Digest::SHA1 qw/sha1_hex/; sub new { my ($class, $args) = @_; my $klass = 'Data::Object::Class::A' . sha1_hex $$ . $args; eval qq| package $klass; use strict; use warnings; use base 'Data::Object::Class'; 1; |; die "can't create klass : $klass $@" if $@; $args->{klass} = $klass; my $self = bless $args, $class; $self->reset; return $self; } sub iterator { my $self = shift; my $data = $self->{data}->[$self->{_position}++]; return unless $data; my $obj = $self->{klass}->new( +{ hooks => $self->{add_hooks}, data => $data, }, ); return $obj; } sub reset { my $self = shift; $self->{_position} = 0; return; } sub next { my $self = shift; $self->iterator; } 1;
test code:
use strict; use warnings; use Data::Object; use URI; use Test::Declare; plan tests => blocks * 3; my @data = ( +{ name => 'nekokak', url => 'http://d.hatena.ne.jp/nekokak/', }, +{ name => 'example', url => 'http://example.com/', }, ); describe 'test Date::Object' => run { test 'do test' => run { my $obj = Data::Object->new( { add_hooks => +{ url => sub { my $val = shift; return URI->new($val); }, }, data => \@data, } ); for my $data (@data) { my $row = $obj->next; is $row->name, $data->{name}; is $row->url, $data->{url}; isa_ok $row->url, 'URI::http'; } }; };
ここではANONクラス作るときにClass::Anonをつかわずに自前でevalしてます。
これもネタなので適当です。