75338209ca044b2172028712fcc4fed5eaecd9df
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / TT / Base.pm
1 package SQL::Translator::Producer::TT::Base;
2
3 # -------------------------------------------------------------------
4 # Copyright (C) 2002-2009 SQLFairy Authors
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
21 =pod
22
23 =head1 NAME
24
25 SQL::Translator::Producer::TT::Base - TT (Template Toolkit) based Producer base
26 class.
27
28 =cut
29
30 use strict;
31
32 use vars qw[ $VERSION @EXPORT_OK ];
33 $VERSION = '1.59';
34
35 use Template;
36 use Data::Dumper;
37 use IO::Handle;
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
64 # Util args access method.
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
69 #           exist in the args are returned as undef.
70 sub args {
71     my $me = shift;
72
73     # No args
74     unless (@_) {
75         return wantarray
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;
98     my $tt = Template->new(
99         #DEBUG    => $me->translator->debug,
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
104     ) || die "Failed to initialize Template object: ".Template->error;
105
106     $tt->process( $tmpl, {
107         $me->tt_default_vars,
108         $me->tt_vars,          # Sub-class hook for adding vars
109     }, \$out )
110     or die "Error processing template '$tmpl': ".$tt->error;
111
112     return $out;
113 }
114
115
116 # Sub class hooks
117 #-----------------------------------------------------------------------------
118
119 sub tt_config { () };
120
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 };
137
138 sub tt_default_vars {
139     my $me = shift;
140     return (
141         translator => $me->translator,
142         schema     => $me->pre_process_schema($me->translator->schema),
143     );
144 }
145
146 sub pre_process_schema { $_[1] }
147
148 sub tt_vars   { () };
149
150 1;
151
152 # -------------------------------------------------------------------
153
154 =pod
155
156 =head1 SYNOPSIS
157
158  # Create a producer using a template in the __DATA__ section.
159  package SQL::Translator::Producer::Foo;
160
161  use base qw/SQL::Translator::Producer::TT::Base/;
162
163  # Convert produce call into a method call on our new class
164  sub produce { return __PACKAGE__->new( translator => shift )->run; };
165
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
172  # Put template in DATA section (or use file with ttfile producer arg)
173  __DATA__
174  Schema
175
176  Database: [% schema.database %]
177  Foo: $foo
178  ...
179
180 =head1 DESCRIPTION
181
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
186 You can find an introduction to this module in L<SQL::Translator::Manual>.
187
188 The 1st thing the module does is convert the produce sub routine call we get
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.
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
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.
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
208 Sub-classes can override these methods to control the templating by giving
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
215 Return hash of Template config to add to that given to the L<Template> C<new>
216 method.
217
218 =head2 tt_schema
219
220  sub tt_schema { "foo.tt"; }
221  sub tt_schema { local $/ = undef; \<DATA>; }
222
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.
226
227 The default implimentation uses the producer arg C<ttfile> as a filename to read
228 the template from. If the arg isn't there it will look for a C<__DATA__> section
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.
231
232 =head2 tt_vars
233
234  sub tt_vars { ( foo => "bar" ); }
235
236 Return hash of template vars to use in the template. Nothing added here
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
260 =head2 pre_process_schema
261
262 WARNING: This method is Experimental so may change!
263
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.
267
268 Gets called from tt_default_vars.
269
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
291 =head2 run
292
293 Called to actually produce the output, calling the sub class hooks. Returns the
294 produced text.
295
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.
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.
307
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.
310
311 =head1 SEE ALSO
312
313 L<perl>,
314 L<SQL::Translator>,
315 L<Template>.
316
317 =head1 TODO
318
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.
322
323 - Pass in template vars from the producer args and command line.
324
325 - Merge in TT::Table.
326
327 - Hooks to pre-process the schema and post-process the output.
328
329 =head1 AUTHOR
330
331 Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
332
333 =cut