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";

Reply via email to