On Sat, 2003-08-09 at 06:55, Dave Rolsky wrote:
> So what I think we really want is this:
>
> my $Wrapper = DT::Wrapper->wrapper( [$class1, $class2, $class3] );
Maybe my approach has some holes, but have a look at the attached and
see what you think ...
#!/usr/bin/perl
#-----------------------------------------------------------------------
package DateTime::AddOneDay;
#-----------------------------------------------------------------------
use DateTime;
# Calling new here gives us one day later than the args asked for.
sub new {
my $class = shift;
my $date = DateTime->new(@_)->add( days => 1);
return bless $date, $class;
}
# Decorator's job is to add one day
sub add_one_day {
return shift->add(days => 1);
}
#-----------------------------------------------------------------------
package DateTime::StrfPirate;
#-----------------------------------------------------------------------
# Only one thing here!
sub strftime {
return "Your strftime method has been pirated by a decorator {evil laugh}.";
}
#-----------------------------------------------------------------------
package DateTime::Now;
#-----------------------------------------------------------------------
use DateTime;
# If now is called on this module we return DateTime->now()
# .. figure that's what people would expect
sub new {
my $class = shift;
my %args = @_;
# Trim out any params that will cause DateTime::now() to keel over
my %useargs;
$useargs{locale} = $args{locale} if $args{locale};
$useargs{time_zone} = $args{time_zone} if $args{time_zone};
# There must be a better way to do that!
return bless DateTime->now(%useargs), $class;
}
# Decorator's real job is to set the time to the current time
sub setnow {
my $self = shift;
my $now = DateTime->now();
$self->set(
hour => $now->hour,
minute => $now->minute,
second => $now->second,
nanosecond => $now->nanosecond
);
return $self;
}
#-----------------------------------------------------------------------
package DateTime::Decorator;
#-----------------------------------------------------------------------
# called 'create' so that a call to 'new' calls the right new :)
sub create {
my $class = shift;
# Don't do Param::Validate because we've been passed all sort of
# things depending on our decorator path
my %args = @_;
# Create our inheritance path. In the real solution, we'd check if
# DateTime was already stated.
@ISA = (@{delete $args{decorators}}, 'DateTime');
# Bless nothing so we have something
my $self = bless \{}, $class;
# And now we have something we can create our object
return bless $self->new(%args), $class;
}
sub decorate {
# unshift more decorators onto @ISA
}
sub decorators {
return @ISA;
}
#-----------------------------------------------------------------------
package main;
#-----------------------------------------------------------------------
my $datetime1 = DateTime::Decorator->create(
decorators => ['DateTime::AddOneDay', 'DateTime::Now'],
year => 2003,
day => 12
);
print '$datetime1->datetime: ' . $datetime1->datetime . "\n";
print '$datetime1->setnow->datetime: ' . $datetime1->setnow->datetime . "\n\n";
my $datetime2 = DateTime::Decorator->create(
decorators => ['DateTime::StrfPirate', 'DateTime::Now'],
# no need for other constructors ..
# ::StrfPirate has no new so we try the next decorator
# ::Now has a new so it gets used .. and it doesn't need any params.
);
$datetime2->add(hours => 123);
print '$datetime2->datetime: ' . $datetime2->datetime . "\n";
print '$datetime2->setnow->datetime: ' . $datetime2->setnow->datetime . "\n";
print '$datetime2->strftime("%c"): ' . $datetime2->strftime("%c") . "\n";