98187b26f61ad970c330287e06695d0a82ebac28
[p5sagit/Excel-Template.git] / lib / Excel / Template / Factory.pm
1 package Excel::Template::Factory;
2
3 use strict;
4
5 my %Manifest = (
6
7 # These are the instantiable nodes
8     'IF'        => 'Excel::Template::Container::Conditional',
9     'LOOP'      => 'Excel::Template::Container::Loop',
10     'ROW'       => 'Excel::Template::Container::Row',
11     'SCOPE'     => 'Excel::Template::Container::Scope',
12     'WORKBOOK'  => 'Excel::Template::Container::Workbook',
13     'WORKSHEET' => 'Excel::Template::Container::Worksheet',
14
15     'BACKREF'   => 'Excel::Template::Element::Backref',
16     'CELL'      => 'Excel::Template::Element::Cell',
17     'FORMULA'   => 'Excel::Template::Element::Formula',
18     'RANGE'     => 'Excel::Template::Element::Range',
19     'VAR'       => 'Excel::Template::Element::Var',
20
21     'FORMAT'    => 'Excel::Template::Container::Format',
22
23 # These are all the Format short-cut objects
24 # They are also instantiable
25     'BOLD'      => 'Excel::Template::Container::Bold',
26     'HIDDEN'    => 'Excel::Template::Container::Hidden',
27     'ITALIC'    => 'Excel::Template::Container::Italic',
28     'LOCKED'    => 'Excel::Template::Container::Locked',
29     'OUTLINE'   => 'Excel::Template::Container::Outline',
30     'SHADOW'    => 'Excel::Template::Container::Shadow',
31     'STRIKEOUT' => 'Excel::Template::Container::Strikeout',
32
33     'KEEP_LEADING_ZEROS' => 'Excel::Template::Container::KeepLeadingZeros',
34
35 # These are the helper objects
36 # They are also in here to make E::T::Factory::isa() work.
37     'CONTEXT'    => 'Excel::Template::Context',
38     'ITERATOR'   => 'Excel::Template::Iterator',
39     'TEXTOBJECT' => 'Excel::Template::TextObject',
40
41     'CONTAINER'  => 'Excel::Template::Container',
42     'ELEMENT'    => 'Excel::Template::Element',
43
44     'BASE'       => 'Excel::Template::Base',
45 );
46
47 my %isBuildable = map { $_ => ~~1 } qw(
48     WORKBOOK WORKSHEET
49     FORMAT BOLD HIDDEN ITALIC LOCKED OUTLINE SHADOW STRIKEOUT
50     IF ROW LOOP SCOPE KEEP_LEADING_ZEROS
51     CELL FORMULA
52     VAR BACKREF RANGE
53 );
54
55 {
56     my %Loaded;
57     sub _load_class
58     {
59         my $self = shift;
60         my ($class) = @_;
61
62         unless ( exists $Loaded{$class} )
63         {
64             (my $filename = $class) =~ s!::!/!g;
65             eval {
66                 require "$filename.pm";
67             }; if ($@) {
68                 die "Cannot find or compile PM file for '$class' ($filename)\n";
69             }
70
71             $Loaded{$class} = ~~1;
72         }
73
74         return ~~1;
75     }
76 }
77
78 {
79     my @param_names = qw(name class isa);
80     sub register
81     {
82         my $self = shift;
83         my %params = @_;
84
85         for (@param_names)
86         {
87             unless ($params{$_})
88             {
89                 warn "$_ was not supplied to register()\n" if $^W;
90                 return;
91             }
92         }
93
94         my $name = uc $params{name};
95         if (exists $Manifest{$name})
96         {
97             warn "$params{name} already exists in the manifest.\n" if $^W;
98             return;
99         }
100
101         my $isa = uc $params{isa};
102         unless (exists $Manifest{$isa})
103         {
104             warn "$params{isa} does not exist in the manifest.\n" if $^W;
105             return;
106         }
107
108         {
109             no strict 'refs';
110             unshift @{"$params{class}::ISA"}, $Manifest{$isa};
111         }
112
113         $self->_load_class( $Manifest{$isa} );
114         $self->_load_class( $params{class} );
115
116         $Manifest{$name} = $params{class};
117         $isBuildable{$name} = ~~1;
118
119         return ~~1;
120     }
121 }
122
123 sub _create
124 {
125     my $self = shift;
126     my $name = uc shift;
127
128     return unless exists $Manifest{$name};
129
130     $self->_load_class( $Manifest{$name} );
131  
132     return $Manifest{$name}->new(@_);
133 }
134
135 sub _create_node
136 {
137     my $self = shift;
138     my $name = uc shift;
139
140     return unless exists $isBuildable{$name};
141
142     return $self->_create($name, @_);
143 }
144
145 sub isa
146 {
147     return unless @_ >= 2;
148     exists $Manifest{uc $_[1]}
149         ? UNIVERSAL::isa($_[0], $Manifest{uc $_[1]})
150         : UNIVERSAL::isa(@_)
151 }
152
153 sub is_embedded
154 {
155     return unless @_ >= 1;
156
157     isa( $_[0], $_ ) && return ~~1 for qw( VAR BACKREF RANGE );
158     return;
159 }
160
161 1;
162 __END__
163
164 =head1 NAME
165
166 Excel::Template::Factory
167
168 =head1 PURPOSE
169
170 To provide a common way to instantiate Excel::Template nodes
171
172 =head1 USAGE
173
174 =head2 register()
175
176 Use this to register your own nodes.
177
178 Example forthcoming.
179
180 =head1 METHODS
181
182 =head2 isa
183
184 This is a customized isa() wrapper for syntactic sugar
185
186 =head2 is_embedded
187
188 =head1 AUTHOR
189
190 Rob Kinyon (rob.kinyon@gmail.com)
191
192 =head1 SEE ALSO
193
194 =cut