package Rose::Object::MakeMethods::DateTime; use strict; use Carp(); our $VERSION = '0.81'; use Rose::Object::MakeMethods; our @ISA = qw(Rose::Object::MakeMethods); use Rose::DateTime::Util(); sub datetime { my($class, $name, $args) = @_; my %methods; my $key = $args->{'hash_key'} || $name; my $interface = $args->{'interface'} || 'get_set'; my $tz = $args->{'tz'}; if($interface eq 'get_set') { $methods{$name} = sub { my($self) = shift; if(@_) { if(@_ == 2) { if($_[0] eq 'format') { return Rose::DateTime::Util::format_date($self->{$key}, ((ref $_[1]) ? @{$_[1]} : $_[1])); } elsif($_[0] eq 'truncate') { return undef unless($self->{$key}); return $self->{$key} unless(ref $self->{$key}); return $self->{$key}->clone->truncate(to => $_[1]); } else { Carp::croak "Invalid arguments for $name attribute: @_" } } elsif(@_ > 1) { Carp::croak "Too many arguments for $name attribute: @_"; } $self->{$key} = Rose::DateTime::Util::parse_date($_[0], $tz || ()) or Carp::croak("Invalid date: '$_[0]'"); } return $self->{$key}; } } elsif($interface eq 'get_set_init') { my $init_method = $args->{'init_method'} || "init_$name"; $methods{$name} = sub { my($self) = shift; if(@_) { if(@_ == 2) { my $arg = $self->$init_method(); $self->{$key} = Rose::DateTime::Util::parse_date($arg, $tz || ()) or Carp::croak("Invalid date: '$arg'"); if($_[0] eq 'format') { return Rose::DateTime::Util::format_date($self->{$key}, ((ref $_[1]) ? @{$_[1]} : $_[1])); } elsif($_[0] eq 'truncate') { return undef unless($self->{$key}); return $self->{$key} unless(ref $self->{$key}); return $self->{$key}->clone->truncate(to => $_[1]); } else { Carp::croak "Invalid arguments for $name attribute: @_" } } elsif(@_ > 1) { Carp::croak "Too many arguments for $name attribute: @_"; } $self->{$key} = Rose::DateTime::Util::parse_date($_[0], $tz || ()) or Carp::croak("Invalid date: '$_[0]'"); } return $self->{$key} if(defined $self->{$key}); my $arg = $self->$init_method(); $self->{$key} = Rose::DateTime::Util::parse_date($arg, $tz || ()) or Carp::croak("Invalid date: '$arg'"); return $self->{$key}; } } else { Carp::croak "Unknown interface: $interface" } return \%methods; } 1; __END__ =head1 NAME Rose::Object::MakeMethods::DateTime - Create methods that store DateTime objects. =head1 SYNOPSIS package MyObject; use Rose::Object::MakeMethods::DateTime ( datetime => [ 'birthday', 'arrival' => { tz => 'UTC' } ], ); ... $obj = MyObject->new(birthday => '1/24/1984 1am'); $dt = $obj->birthday; # DateTime object $bday = $obj->birthday(format => '%B %E'); # 'January 24th' # Shortcut for $obj->birthday->clone->truncate(to => 'month'); $month = $obj->birthday(truncate => 'month'); $obj->birthday('blah'); # croaks - invalid date! $obj->birthday('1999-04-31'); # croaks - invalid date! =head1 DESCRIPTION L is a method maker that inherits from L. See the L documentation to learn about the interface. The method types provided by this module are described below. All methods work only with hash-based objects. =head1 METHODS TYPES =over 4 =item B Create get/set methods for scalar attributes that store L objects. =over 4 =item Options =over 4 =item C The key inside the hash-based object to use for the storage of this attribute. Defaults to the name of the method. =item C The name of the method to call when initializing the value of an undefined attribute. This option is only applicable when using the C interface. Defaults to the method name with the prefix C added. This method should return a value that can be parsed by L's the L function. If the return value is a L object, it will have its time zone set (see the C option below) using L's L method. =item C Chooses one of the two possible interfaces. Defaults to C. =item C The time zone of the L object to be stored. If present, this value will be passed as the second argument to L's the L function when creating L objects for storage. If absent, L objects will use the default time zone of the L class, which is set by L's L class method. See the L documentation for more information. =back =item Interfaces =over 4 =item C Creates a get/set accessor method for an object attribute that stores a L object. When called with a single argument, the argument is passed through L's L function in order to create the L object that is stored. The current value of the attribute is returned. Passing a value that is not understood by L's L function causes a fatal error. When called with two arguments and the first argument is the string 'format', then the second argument is taken as a format specifier which is passed to L's L function. The formatted string is returned. In other words, this: $obj->birthday(format => '%m/%d/%Y'); Is just a shortcut for this: Rose::DateTime::Util::format_date($obj->birthday, '%m/%d/%Y'); When called with two arguments and the first argument is the string 'truncate', then the second argument is taken as a truncation specifier which is passed to L's L method called on a clone of the existing L object. The cloned, truncated L object is returned. In other words, this: $obj->birthday(truncate => 'month'); Is just a shortcut for this: $obj->birthday->clone->truncate(to => 'month'); Passing more than two arguments or passing two arguments where the first argument is not 'format' or 'truncate' will cause a fatal error. =item C Behaves like the C interface unless the value of the attribute is undefined. In that case, the method specified by the C option is called, the return value is passed through L's L function, and the attribute is set to the return value. An init method that returns a value that is not understood by L's L function will cause a fatal error. =back =back Example: package MyObject; use Rose::Object::MakeMethods::DateTime ( datetime => [ 'birthday', 'arrival' => { tz => 'UTC' } ], 'datetime --get_set_init' => [ 'departure' => { tz => 'UTC' } ], ); sub init_departure { DateTime->new(month => 1, day => 10, year => 2000, time_zone => 'America/Chicago'); } ... $obj = MyObject->new(birthday => '1/24/1984 1am'); $dt = $obj->birthday; # DateTime object $bday = $obj->birthday(format => '%B %E'); # 'January 24th' # Shortcut for $obj->birthday->clone->truncate(to => 'month'); $month = $obj->birthday(truncate => 'month'); $obj->birthday('blah'); # croaks - invalid date! $obj->birthday('1999-04-31'); # croaks - invalid date! # DateTime object with time zone set to UTC $dt = $obj->arrival('2005-21-01 4pm'); # DateTime object with time zone set to UTC, not America/Chicago! # Start with 2000-01-10T00:00:00 America/Chicago, # then set_time_zone('UTC'), # which results in: 2000-01-10T06:00:00 UTC $dt = $obj->departure; print $dt; # "2000-01-10T06:00:00" =back =head1 AUTHOR John C. Siracusa (siracusa@gmail.com) =head1 LICENSE Copyright (c) 2006 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.