1

I've got several Modules that have a number of date time related attributes that accept a datestamp and return a human readable string ( dd Mon yyyy hh:mm:ss ).

package ModuleOne;

use Moose;

extends 'ModuleBase';

has date_attr_one => ( ... );

and then ...

package ModuleTwo;

use Moose;

extends 'ModuleBase';

has date_attr_mouse => ( ... );

As it's currently working I'm using an 'around' attribute modifier so that if there's no parameter return the a date in the format of '03 May 2012 12:33:42'. If there is a parameter in the format of '03 May 2012 12:33:42' the I want to set that as a datestamp.

So, in ModuleOne, there would be:

has date_attr_one => ( ... );

followed by:

around 'date_attr_one' => sub { ... }

Same type of thing occurs in the second module.

The problem I'm having is that there are multiple modules doing this and each of them is using the 'around' modifier and the same duplicated code. I'd like to move that around modifier into the base class so every Module that extends the base class can use that modifier. I tried putting it into the base class using a regex like: (in the base class)

around qr/date_attr_one/ => sub { ... }

I put some print statements in there that never executed. Roles don't allow such a thing.

Is there a way to move that around modifier into the base class so every Module that extends the base class can use that modifier where the attributes would have different names in each model?

So, as in the example above, the base class' around attribute modifier would need to handle $self->date_attr_one and $self->date_attr_mouse, among others.

jmcneirney
  • 1,374
  • 8
  • 23
  • Why do you want to store as a "datestamp" if you always return it as `03 May 2012 12:33:42`? – ikegami May 08 '12 at 21:05
  • 3rd party api stores it as a datestamp ( unix time stamp ). What is displayed by: perl -e 'print time()' – jmcneirney May 08 '12 at 22:22
  • You realize that around, before, etc are all _method_ modifiers, right? They just happen to be modifying the accessor method installed for that attribute. – RsrchBoy May 09 '12 at 19:16

1 Answers1

2

If you create a package like the one below, all you need in your classes is:

has date => (
   is     => 'rw',
   isa    => 'My::Date',
   coerce => 1,
);

Example code:

my $o = My::Class->new(date => '03 May 2012 12:33:42');
say $o->date();
say 0+$o->date();

$o->date(1336062822);
say $o->date();
say 0+$o->date();

The aforementioned module:

package My::Date;

use strict;
use warnings;

use Moose;
use Moose::Util::TypeConstraints;

use DateTime::Format::Strptime qw( );
use POSIX                      qw( strftime );

my $format = DateTime::Format::Strptime->new(
   pattern   => '%d %b %Y %H:%M:%S',
   locale    => 'en_US',
   time_zone => 'local',
   on_error  => 'croak',
);

has epoch => (
   is       => 'rw',
   isa      => 'Num',
   required => 1,
);

sub as_string {
   return strftime('%d %b %Y %H:%M:%S', localtime( $_[0]->epoch ));
}

coerce __PACKAGE__,
   from 'Num',
      via { __PACKAGE__->new( epoch => $_ ) },
   from 'Str',
      via { __PACKAGE__->new( epoch => $format->parse_datetime($_)->epoch ) };

use overload (
   '""' => sub { $_[0]->as_string },
   '0+' => sub { $_[0]->epoch },
   fallback => 1,
);

1;
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • This worked. Thanks a lot. Is there anyway to avoid that '0+' in 0+$self->date(). – jmcneirney May 10 '12 at 14:10
  • I'm not sure what you mean by that. You asked for an interface that made it impossible to return the epoch time, so presumably you don't need the epoch time, so there's nothing to get rid of since you're not going to use it at all. I figured not being able to get the epoch time was a rather limiting, so I made it so you could get it by treating `$self->date` as a number. You can also use `$self->date->epoch`. – ikegami May 10 '12 at 15:31
  • Heh. Thanks. You're right. :) I had it in a test and it just seemed awkward. – jmcneirney May 10 '12 at 17:53
  • @jmcneirney, In case it's not clear, both the constructor and the accessor accept epoch dates and formatted dates. (Also accepts My::Date objects.) – ikegami May 10 '12 at 18:06
  • Yeah, from the coercion. Thanks again. – jmcneirney May 10 '12 at 18:21