Commit | Line | Data |
f5f03b78 |
1 | package SQL::Translator::Producer::TT::Base; |
2 | |
3 | # ------------------------------------------------------------------- |
478f608d |
4 | # Copyright (C) 2002-2009 SQLFairy Authors |
f5f03b78 |
5 | # |
6 | # This program is free software; you can redistribute it and/or |
7 | # modify it under the terms of the GNU General Public License as |
8 | # published by the Free Software Foundation; version 2. |
9 | # |
10 | # This program is distributed in the hope that it will be useful, but |
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | # General Public License for more details. |
14 | # |
15 | # You should have received a copy of the GNU General Public License |
16 | # along with this program; if not, write to the Free Software |
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
18 | # 02111-1307 USA |
19 | # ------------------------------------------------------------------- |
20 | |
11a8c77a |
21 | =pod |
f5f03b78 |
22 | |
23 | =head1 NAME |
24 | |
11a8c77a |
25 | SQL::Translator::Producer::TT::Base - TT (Template Toolkit) based Producer base |
26 | class. |
f5f03b78 |
27 | |
28 | =cut |
29 | |
f5f03b78 |
30 | use strict; |
31 | |
da06ac74 |
32 | use vars qw[ $VERSION @EXPORT_OK ]; |
4ab3763d |
33 | $VERSION = '1.59'; |
f5f03b78 |
34 | |
35 | use Template; |
36 | use Data::Dumper; |
bfd86e76 |
37 | use IO::Handle; |
f5f03b78 |
38 | use Exporter; |
39 | use base qw(Exporter); |
40 | @EXPORT_OK = qw(produce); |
41 | |
42 | use SQL::Translator::Utils 'debug'; |
43 | |
44 | # Hack to convert the produce call into an object. ALL sub-classes need todo |
45 | # this so that the correct class gets created. |
46 | sub produce { |
47 | return __PACKAGE__->new( translator => shift )->run; |
48 | }; |
49 | |
50 | sub new { |
51 | my $proto = shift; |
52 | my $class = ref $proto || $proto; |
53 | my %args = @_; |
54 | |
55 | my $me = bless {}, $class; |
56 | $me->{translator} = delete $args{translator} || die "Need a translator."; |
57 | |
58 | return $me; |
59 | } |
60 | |
61 | sub translator { shift->{translator}; } |
62 | sub schema { shift->{translator}->schema(@_); } |
63 | |
7f3fc883 |
64 | # Util args access method. |
f5f03b78 |
65 | # No args - Return hashref (the actual hash in Translator) or hash of args. |
66 | # 1 arg - Return that named args value. |
67 | # Args - List of names. Return values of the given arg names in list context |
68 | # or return as hashref in scalar context. Any names given that don't |
7f3fc883 |
69 | # exist in the args are returned as undef. |
f5f03b78 |
70 | sub args { |
71 | my $me = shift; |
72 | |
73 | # No args |
74 | unless (@_) { |
7f3fc883 |
75 | return wantarray |
f5f03b78 |
76 | ? %{ $me->{translator}->producer_args } |
77 | : $me->{translator}->producer_args |
78 | ; |
79 | } |
80 | |
81 | # 1 arg. Return the value whatever the context. |
82 | return $me->{translator}->producer_args->{$_[0]} if @_ == 1; |
83 | |
84 | # More args so return values list or hash ref |
85 | my %args = %{ $me->{translator}->producer_args }; |
86 | return wantarray ? @args{@_} : { map { ($_=>$args{$_}) } @_ }; |
87 | } |
88 | |
89 | # Run the produce and return the result. |
90 | sub run { |
91 | my $me = shift; |
92 | my $scma = $me->schema; |
93 | my %args = %{$me->args}; |
94 | my $tmpl = $me->tt_schema or die "No template!"; |
95 | |
96 | debug "Processing template $tmpl\n"; |
97 | my $out; |
7f3fc883 |
98 | my $tt = Template->new( |
f5f03b78 |
99 | #DEBUG => $me->translator->debug, |
7f3fc883 |
100 | ABSOLUTE => 1, # Set so we can use from the command line sensibly |
101 | RELATIVE => 1, # Maybe the cmd line code should set it! Security! |
102 | $me->tt_config, # Hook for sub-classes to add config |
103 | %args, # Allow any TT opts to be passed in the producer_args |
f5f03b78 |
104 | ) || die "Failed to initialize Template object: ".Template->error; |
105 | |
7f3fc883 |
106 | $tt->process( $tmpl, { |
107 | $me->tt_default_vars, |
108 | $me->tt_vars, # Sub-class hook for adding vars |
109 | }, \$out ) |
f5f03b78 |
110 | or die "Error processing template '$tmpl': ".$tt->error; |
111 | |
112 | return $out; |
113 | } |
114 | |
11a8c77a |
115 | |
116 | # Sub class hooks |
117 | #----------------------------------------------------------------------------- |
118 | |
119 | sub tt_config { () }; |
120 | |
bfd86e76 |
121 | sub tt_schema { |
122 | my $me = shift; |
123 | my $class = ref $me; |
124 | |
125 | my $file = $me->args("ttfile"); |
126 | return $file if $file; |
127 | |
128 | no strict 'refs'; |
129 | my $ref = *{"$class\:\:DATA"}{IO}; |
130 | if ( $ref->opened ) { |
131 | local $/ = undef; # Slurp mode |
132 | return \<$ref>; |
133 | } |
134 | |
135 | undef; |
136 | }; |
f5f03b78 |
137 | |
f5f03b78 |
138 | sub tt_default_vars { |
139 | my $me = shift; |
140 | return ( |
141 | translator => $me->translator, |
bfd86e76 |
142 | schema => $me->pre_process_schema($me->translator->schema), |
f5f03b78 |
143 | ); |
144 | } |
145 | |
bfd86e76 |
146 | sub pre_process_schema { $_[1] } |
147 | |
7f3fc883 |
148 | sub tt_vars { () }; |
149 | |
f5f03b78 |
150 | 1; |
151 | |
152 | # ------------------------------------------------------------------- |
153 | |
154 | =pod |
155 | |
11a8c77a |
156 | =head1 SYNOPSIS |
157 | |
466c88de |
158 | # Create a producer using a template in the __DATA__ section. |
11a8c77a |
159 | package SQL::Translator::Producer::Foo; |
160 | |
161 | use base qw/SQL::Translator::Producer::TT::Base/; |
162 | |
f33f9d70 |
163 | # Convert produce call into a method call on our new class |
11a8c77a |
164 | sub produce { return __PACKAGE__->new( translator => shift )->run; }; |
165 | |
11a8c77a |
166 | # Configure the Template object. |
167 | sub tt_config { ( INTERPOLATE => 1 ); } |
168 | |
169 | # Extra vars to add to the template |
170 | sub tt_vars { ( foo => "bar" ); } |
171 | |
bfd86e76 |
172 | # Put template in DATA section (or use file with ttfile producer arg) |
173 | __DATA__ |
174 | Schema |
f33f9d70 |
175 | |
bfd86e76 |
176 | Database: [% schema.database %] |
177 | Foo: $foo |
178 | ... |
179 | |
11a8c77a |
180 | =head1 DESCRIPTION |
181 | |
11a8c77a |
182 | A base class producer designed to be sub-classed to create new TT based |
183 | producers cheaply - by simply giving the template to use and sprinkling in some |
184 | extra template variables and config. |
185 | |
466c88de |
186 | You can find an introduction to this module in L<SQL::Translator::Manual>. |
187 | |
11a8c77a |
188 | The 1st thing the module does is convert the produce sub routine call we get |
f33f9d70 |
189 | from SQL::Translator into a method call on an object, which we can then |
190 | sub-class. This is done with the following code which needs to appear in B<all> |
191 | sub classes. |
11a8c77a |
192 | |
193 | # Convert produce call into an object method call |
194 | sub produce { return __PACKAGE__->new( translator => shift )->run; }; |
195 | |
196 | See L<PRODUCER OBJECT> below for details. |
197 | |
f33f9d70 |
198 | The upshot of this is we can make new template producers by sub classing this |
199 | base class, adding the above snippet and a template. |
200 | The module also provides a number of hooks into the templating process, |
201 | see L<SUB CLASS HOOKS> for details. |
11a8c77a |
202 | |
203 | See the L<SYNOPSIS> above for an example of creating a simple producer using |
204 | a single template stored in the producers DATA section. |
205 | |
206 | =head1 SUB CLASS HOOKS |
207 | |
f33f9d70 |
208 | Sub-classes can override these methods to control the templating by giving |
11a8c77a |
209 | the template source, adding variables and giving config to the Tempate object. |
210 | |
211 | =head2 tt_config |
212 | |
213 | sub tt_config { ( INTERPOLATE => 1 ); } |
214 | |
f33f9d70 |
215 | Return hash of Template config to add to that given to the L<Template> C<new> |
216 | method. |
11a8c77a |
217 | |
218 | =head2 tt_schema |
219 | |
220 | sub tt_schema { "foo.tt"; } |
221 | sub tt_schema { local $/ = undef; \<DATA>; } |
222 | |
f33f9d70 |
223 | The template to use, return a file name or a scalar ref of TT |
224 | source, or an L<IO::Handle>. See L<Template> for details, as the return from |
225 | this is passed on to it's C<produce> method. |
11a8c77a |
226 | |
227 | The default implimentation uses the producer arg C<ttfile> as a filename to read |
f33f9d70 |
228 | the template from. If the arg isn't there it will look for a C<__DATA__> section |
bfd86e76 |
229 | in the class, reading it as template source if found. Returns undef if both |
230 | these fail, causing the produce call to fail with a 'no template!' error. |
11a8c77a |
231 | |
232 | =head2 tt_vars |
233 | |
234 | sub tt_vars { ( foo => "bar" ); } |
235 | |
f33f9d70 |
236 | Return hash of template vars to use in the template. Nothing added here |
11a8c77a |
237 | by default, but see L<tt_default_vars> for the variables you get for free. |
238 | |
239 | =head2 tt_default_vars |
240 | |
241 | Return a hash-ref of the default vars given to the template. |
242 | You wouldn't normally over-ride this, just inherit the default implimentation, |
243 | to get the C<translator> & C<schema> variables, then over-ride L<tt_vars> to add |
244 | your own. |
245 | |
246 | The current default variables are: |
247 | |
248 | =over 4 |
249 | |
250 | =item schema |
251 | |
252 | The schema to template. |
253 | |
254 | =item translator |
255 | |
256 | The L<SQL::Translator> object. |
257 | |
258 | =back |
259 | |
bfd86e76 |
260 | =head2 pre_process_schema |
261 | |
262 | WARNING: This method is Experimental so may change! |
263 | |
f33f9d70 |
264 | Called with the L<SQL::Translator::Schema> object and should return one (it |
265 | doesn't have to be the same one) that will become the C<schema> varibale used |
266 | in the template. |
bfd86e76 |
267 | |
268 | Gets called from tt_default_vars. |
269 | |
11a8c77a |
270 | =head1 PRODUCER OBJECT |
271 | |
272 | The rest of the methods in the class set up a sub-classable producer object. |
273 | You normally just inherit them. |
274 | |
275 | =head2 new |
276 | |
277 | my $tt_producer = TT::Base->new( translator => $translator ); |
278 | |
279 | Construct a new TT Producer object. Takes a single, named arg of the |
280 | L<SQL::Translator> object running the translation. Dies if this is not given. |
281 | |
282 | =head2 translator |
283 | |
284 | Return the L<SQL::Translator> object. |
285 | |
286 | =head2 schema |
287 | |
288 | Return the L<SQL::Translator::Schema> we are translating. This is equivilent |
289 | to C<< $tt_producer->translator->schema >>. |
290 | |
f33f9d70 |
291 | =head2 run |
292 | |
293 | Called to actually produce the output, calling the sub class hooks. Returns the |
294 | produced text. |
295 | |
11a8c77a |
296 | =head2 args |
297 | |
298 | Util wrapper method around C<< TT::Base->translator->producer_args >> for |
299 | (mostley) readonly access to the producer args. How it works depends on the |
300 | number of arguments you give it and the context. |
301 | |
302 | No args - Return hashref (the actual hash in Translator) or hash of args. |
303 | 1 arg - Return value of the arg with the passed name. |
f33f9d70 |
304 | 2+ args - List of names. In list context returns values of the given arg |
305 | names, returns as a hashref in scalar context. Any names given |
306 | that don't exist in the args are returned as undef. |
11a8c77a |
307 | |
f33f9d70 |
308 | This is still a bit messy but is a handy way to access the producer args when |
309 | you use your own to drive the templating. |
11a8c77a |
310 | |
f33f9d70 |
311 | =head1 SEE ALSO |
f5f03b78 |
312 | |
f33f9d70 |
313 | L<perl>, |
314 | L<SQL::Translator>, |
315 | L<Template>. |
f5f03b78 |
316 | |
317 | =head1 TODO |
318 | |
11a8c77a |
319 | - Add support for a sqlf template repository, set as an INCLUDE_PATH, |
320 | so that sub-classes can easily include file based templates using relative |
321 | paths. |
f5f03b78 |
322 | |
f33f9d70 |
323 | - Pass in template vars from the producer args and command line. |
324 | |
f5f03b78 |
325 | - Merge in TT::Table. |
326 | |
11a8c77a |
327 | - Hooks to pre-process the schema and post-process the output. |
328 | |
f33f9d70 |
329 | =head1 AUTHOR |
f5f03b78 |
330 | |
f33f9d70 |
331 | Mark Addison E<lt>grommit@users.sourceforge.netE<gt>. |
f5f03b78 |
332 | |
333 | =cut |