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