package Excel::Template::Factory;
use strict;
my %Manifest = (
# These are the instantiable nodes
'IF' => 'Excel::Template::Container::Conditional',
'LOOP' => 'Excel::Template::Container::Loop',
'ROW' => 'Excel::Template::Container::Row',
'SCOPE' => 'Excel::Template::Container::Scope',
'WORKBOOK' => 'Excel::Template::Container::Workbook',
'WORKSHEET' => 'Excel::Template::Container::Worksheet',
'BACKREF' => 'Excel::Template::Element::Backref',
'CELL' => 'Excel::Template::Element::Cell',
'FORMULA' => 'Excel::Template::Element::Formula',
'FREEZEPANES' => 'Excel::Template::Element::FreezePanes',
'MERGE_RANGE' => 'Excel::Template::Element::MergeRange',
'IMAGE' => 'Excel::Template::Element::Image',
'RANGE' => 'Excel::Template::Element::Range',
'VAR' => 'Excel::Template::Element::Var',
'FORMAT' => 'Excel::Template::Container::Format',
# These are all the Format short-cut objects
# They are also instantiable
'BOLD' => 'Excel::Template::Container::Bold',
'HIDDEN' => 'Excel::Template::Container::Hidden',
'ITALIC' => 'Excel::Template::Container::Italic',
'LOCKED' => 'Excel::Template::Container::Locked',
'OUTLINE' => 'Excel::Template::Container::Outline',
'SHADOW' => 'Excel::Template::Container::Shadow',
'STRIKEOUT' => 'Excel::Template::Container::Strikeout',
'KEEP_LEADING_ZEROS' => 'Excel::Template::Container::KeepLeadingZeros',
# These are the helper objects
# They are also in here to make E::T::Factory::isa() work.
'CONTEXT' => 'Excel::Template::Context',
'ITERATOR' => 'Excel::Template::Iterator',
'TEXTOBJECT' => 'Excel::Template::TextObject',
'CONTAINER' => 'Excel::Template::Container',
'ELEMENT' => 'Excel::Template::Element',
'BASE' => 'Excel::Template::Base',
);
my %isBuildable = map { $_ => ~~1 } qw(
WORKBOOK WORKSHEET
FORMAT BOLD HIDDEN ITALIC LOCKED OUTLINE SHADOW STRIKEOUT
IF ROW LOOP SCOPE KEEP_LEADING_ZEROS
CELL FORMULA FREEZEPANES IMAGE MERGE_RANGE
VAR BACKREF RANGE
);
{
my %Loaded;
sub _load_class
{
my $self = shift;
my ($class) = @_;
unless ( exists $Loaded{$class} )
{
(my $filename = $class) =~ s!::!/!g;
eval {
require "$filename.pm";
}; if ($@) {
die "Cannot find or compile PM file for '$class' ($filename) because $@\n";
}
$Loaded{$class} = ~~1;
}
return ~~1;
}
}
{
my @param_names = qw(name class isa);
sub register
{
my $self = shift;
my %params = @_;
for (@param_names)
{
unless ($params{$_})
{
warn "$_ was not supplied to register()\n" if $^W;
return;
}
}
my $name = uc $params{name};
if (exists $Manifest{$name})
{
warn "$params{name} already exists in the manifest.\n" if $^W;
return;
}
my $isa = uc $params{isa};
unless (exists $Manifest{$isa})
{
warn "$params{isa} does not exist in the manifest.\n" if $^W;
return;
}
{
no strict 'refs';
unshift @{"$params{class}::ISA"}, $Manifest{$isa};
}
$self->_load_class( $Manifest{$isa} );
$self->_load_class( $params{class} );
$Manifest{$name} = $params{class};
$isBuildable{$name} = ~~1;
return ~~1;
}
}
sub _create
{
my $self = shift;
my $name = uc shift;
return unless exists $Manifest{$name};
$self->_load_class( $Manifest{$name} );
return $Manifest{$name}->new(@_);
}
sub _create_node
{
my $self = shift;
my $name = uc shift;
return unless exists $isBuildable{$name};
return $self->_create($name, @_);
}
sub isa
{
return unless @_ >= 2;
exists $Manifest{uc $_[1]}
? UNIVERSAL::isa($_[0], $Manifest{uc $_[1]})
: UNIVERSAL::isa(@_)
}
sub is_embedded
{
return unless @_ >= 1;
isa( $_[0], $_ ) && return ~~1 for qw( VAR BACKREF RANGE );
return;
}
1;
__END__
=head1 NAME
Excel::Template::Factory
=head1 PURPOSE
To provide a common way to instantiate Excel::Template nodes
=head1 USAGE
=head2 register()
Use this to register your own nodes.
Example forthcoming.
=head1 METHODS
=head2 isa
This is a customized isa() wrapper for syntactic sugar
=head2 is_embedded
=head1 AUTHOR
Rob Kinyon (rob.kinyon@gmail.com)
=head1 SEE ALSO
=cut