# $Id$ package Items; use strict; use warnings; use version; our $VERSION = qv('0.0.1'); use vars qw($AUTOLOAD); use Carp; use English qw( -no_match_vars ); use Cache::FastMemoryCache; use Contextual::Return; use DateTime; use Sub::Installer; { # item cache keys: my $LAST_ITEM_ID = 0; sub next_id { return ++$LAST_ITEM_ID } # items cache: my $cache = Cache::FastMemoryCache->new( { namespace => __PACKAGE__ } ); # item retriever sub retrieve { my ( $class, $id ) = @_; return $cache->get($id); } # item creator sub create { my ( $class, %data ) = @_; $data{__id} = $class->next_id; $data{__created} = time; my $self = bless \%data, ref $class || $class; $cache->set( $self->id, $self ); return $self; } # attributes inflaters my $inflaters = { created => sub { DateTime->from_epoch( epoch => $_[0]->created ) }, }; # add an inflater method sub inflater { my ( $class, $attr, $coderef ) = @_; $inflaters->{$attr} = $coderef; return $class; } # inflate an object's attribute sub inflate { my ( $self, $attr ) = @_; if ( exists $inflaters->{$attr} ) { return $inflaters->{$attr}->($self); } return croak "Don't know how to inflate '$attr'!"; } } # easy create/retrieve hack sub new { my $class = shift; return @_ == 1 ? $class->retrieve(@_) : $class->create(@_); } # "special" accessor for the primary item key sub id { return $_[0]->{__id} } # "special" accessor for the created timestamp sub created { my $self = shift; return ( OBJREF { $self->inflate('created') } DEFAULT { $self->{__created} } ); } # "universal" accessor/mutator sub AUTOLOAD { ( my $attr = $AUTOLOAD ) =~ s/ ^ (.*) :: //xms; my $class = $1 || __PACKAGE__; my $sub = sub { my $self = shift; if (@_) { $self->{$attr} = shift; } return if !exists $self->{$attr}; return ( OBJREF { $self->inflate($attr) } DEFAULT { $self->{$attr} } ); }; $class->install_sub( { $attr => $sub } ); return $sub->(@_); } sub DESTROY { } 1;