Doc tweaks
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / TT / Table.pm
CommitLineData
0be5b227 1package SQL::Translator::Producer::TT::Table;
2
3# -------------------------------------------------------------------
f65806ce 4# $Id: Table.pm,v 1.2 2004-07-30 22:04:25 kycl4rk Exp $
0be5b227 5# -------------------------------------------------------------------
6# Copyright (C) 2002-4 SQLFairy Authors
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License as
10# published by the Free Software Foundation; version 2.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20# 02111-1307 USA
21# -------------------------------------------------------------------
22
23=pod
24
25=head1 NAME
26
27SQL::Translator::Producer::TT::Table -
28 Produces output using the Template Toolkit from a SQL schema, per table.
29
30=head1 SYNOPSIS
31
32 # Normal STDOUT version
33 #
34 my $translator = SQL::Translator->new(
35 from => 'MySQL',
36 filename => 'foo_schema.sql',
37 to => 'TT::Table',
38 producer_args => {
39 tt_table => 'foo_table.tt',
40 },
41 );
42 print $translator->translate;
43
44 # To generate a file per table
45 #
46 my $translator = SQL::Translator->new(
47 from => 'MySQL',
48 filename => 'foo_schema.sql',
49 to => 'TT::Table',
50 producer_args => {
51 tt_table => 'foo_table.tt.html',
52 mk_files => 1,
53 mk_files_base => "./doc/tables",
54 mk_file_ext => ".html",
55 on_exists => "replace",
56 },
57 );
58 #
59 # ./doc/tables/ now contains the templated tables as $tablename.html
60 #
61
62=head1 DESCRIPTION
63
f65806ce 64Produces schema output using a given Template Tookit template,
65processing that template for each table in the schema. Optionally
66allows you to write the result for each table to a separate file.
0be5b227 67
68It needs one additional producer_arg of C<tt_table> which is the file
f65806ce 69name of the template to use. This template will be passed a template
70var of C<table>, which is the current
71C<SQL::Translator::Producer::Table> table we are producing, which you
72can then use to walk the schema via the methods documented in that
73module. You also get C<schema> as a shortcut to the
74C<SQL::Translator::Producer::Schema> for the table and C<translator>,
75the C<SQL::Translator> object for this parse in case you want to get
76access to any of the options etc set here.
0be5b227 77
78Here's a brief example of what the template could look like:
79
80 [% table.name %]
81 ================
82 [% FOREACH field = table.get_fields %]
83 [% field.name %] [% field.data_type %]([% field.size %])
84 [% END -%]
85
86See F<t/data/template/table.tt> for a more complete example.
87
f65806ce 88You can also set any of the options used to initiallize the Template
89object by adding them to your producer_args. See Template Toolkit docs
90for details of the options.
0be5b227 91
92 $translator = SQL::Translator->new(
93 to => 'TT',
94 producer_args => {
95 ttfile => 'foo_template.tt',
96 INCLUDE_PATH => '/foo/templates/tt',
97 INTERPOLATE => 1,
98 },
99 );
100
f65806ce 101If you set C<mk_files> and its additional options the producer will
102write a separate file for each table in the schema. This is useful for
103producing things like HTML documentation where every table gets its
104own page (you could also use TTSchema producer to add an index page).
105Its also particulary good for code generation where you want to
106produce a class file per table.
0be5b227 107
108=head1 OPTIONS
109
110=over 4
111
112=item tt_table
113
114File name of the template to run for each table.
115
116=item mk_files
117
f65806ce 118Set to true to output a file for each table in the schema (as well as
119returning the whole lot back to the Translalor and hence STDOUT). The
120file will be named after the table, with the optional C<mk_files_ext>
121added and placed in the directory C<mk_files_base>.
0be5b227 122
123=item mk_files_ext
124
125Extension (without the dot) to add to the filename when using mk_files.
126
127=item mk_files_base = DIR
128
f65806ce 129Dir to build the table files into when using mk_files. Defaults to the
130current directory.
0be5b227 131
132=item mk_file_dir
133
f65806ce 134Set true and if the file needs to written to a directory that doesn't
135exist, it will be created first.
0be5b227 136
137=item on_exists [Default:replace]
138
f65806ce 139What to do if we are running with mk_files and a file already exists
140where we want to write our output. One of "skip", "die", "replace",
141"insert". The default is die.
0be5b227 142
f65806ce 143B<replace> - Over-write the existing file with the new one, clobbering
144anything already there.
0be5b227 145
f65806ce 146B<skip> - Leave the origional file as it was and don't write the new
147version anywhere.
0be5b227 148
149B<die> - Die with an existing file error.
150
f65806ce 151B<insert> - Insert the generated output into the file bewteen a set of
152special comments (defined by the following options.) Any code between
153the comments will be overwritten (ie the results from a previous
154produce) but the rest of the file is left alone (your custom code).
155This is particularly useful for code generation as it allows you to
156generate schema derived code and then add your own custom code using
157it to file. Then when the scheam changes you just re-produce and
158insert the new code.
0be5b227 159
160=item insert_comment_start
161
f65806ce 162The comment to look for in the file when on_exists is insert. Default
163is C<SQLF INSERT START>. Must appear on it own line, with only
164whitespace either side, to be recognised.
0be5b227 165
166=item insert_comment_end
167
f65806ce 168The end comment to look for in the file when on_exists is insert.
169Default is C<SQLF INSERT END>. Must appear on it own line, with only
170whitespace either side, to be recognised.
0be5b227 171
172=back
173
174=cut
175
176# -------------------------------------------------------------------
177
178use strict;
179
180use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
f65806ce 181$VERSION = sprintf "%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/;
0be5b227 182$DEBUG = 0 unless defined $DEBUG;
183
184use File::Path;
185use Template;
186use Data::Dumper;
187use Exporter;
188use base qw(Exporter);
189@EXPORT_OK = qw(produce);
190
191use SQL::Translator::Utils 'debug';
192
193my $Translator;
194
195sub produce {
196 $Translator = shift;
197 local $DEBUG = $Translator->debug;
198 my $scma = $Translator->schema;
199 my $pargs = $Translator->producer_args;
200 my $file = $pargs->{'tt_table'} or die "No template file given!";
201 $pargs->{on_exists} ||= "die";
202
203 debug "Processing template $file\n";
204 my $out;
205 my $tt = Template->new(
206 DEBUG => $DEBUG,
207 ABSOLUTE => 1, # Set so we can use from the command line sensibly
208 RELATIVE => 1, # Maybe the cmd line code should set it! Security!
209 %$pargs, # Allow any TT opts to be passed in the producer_args
210 ) || die "Failed to initialize Template object: ".Template->error;
211
212 for my $tbl ( sort {$a->order <=> $b->order} $scma->get_tables ) {
213 my $outtmp;
214 $tt->process( $file, {
215 translator => $Translator,
216 schema => $scma,
217 table => $tbl,
218 }, \$outtmp )
219 or die "Error processing template '$file' for table '".$tbl->name
220 ."': ".$tt->error;
221 $out .= $outtmp;
222
223 # Write out the file...
224 write_file( table_file($tbl), $outtmp ) if $pargs->{mk_files};
225 }
226
227 return $out;
228};
229
230# Work out the filename for a given table.
231sub table_file {
232 my ($tbl) = shift;
233 my $pargs = $Translator->producer_args;
234 my $root = $pargs->{mk_files_base};
235 my $ext = $pargs->{mk_file_ext};
236 return "$root/$tbl.$ext";
237}
238
239# Write the src given to the file given, handling the on_exists arg.
240sub write_file {
241 my ($file, $src) = @_;
242 my $pargs = $Translator->producer_args;
243 my $root = $pargs->{mk_files_base};
244
245 if ( -e $file ) {
246 if ( $pargs->{on_exists} eq "skip" ) {
247 warn "Skipping existing $file\n";
248 return 1;
249 }
250 elsif ( $pargs->{on_exists} eq "die" ) {
251 die "File $file already exists.\n";
252 }
253 elsif ( $pargs->{on_exists} eq "replace" ) {
254 warn "Replacing $file.\n";
255 }
256 elsif ( $pargs->{on_exists} eq "insert" ) {
257 warn "Inserting into $file.\n";
258 $src = insert_code($file, $src);
259 }
260 else {
261 die "Unknown on_exists action: $pargs->{on_exists}\n";
262 }
263 }
264 else {
265 warn "Creating $file.\n";
266 }
267
268 my ($dir) = $file =~ m!^(.*)/!; # Want greedy, eveything before the last /
269 if ( $dir and not -d $dir and $pargs->{mk_file_dir} ) { mkpath($dir); }
270
271 debug "Writing to $file\n";
272 open( FILE, ">$file") or die "Error opening file $file : $!\n";
273 print FILE $src;
274 close(FILE);
275}
276
277# Reads file and inserts code between the insert comments and returns the new
278# source.
279sub insert_code {
280 my ($file, $src) = @_;
281 my $pargs = $Translator->producer_args;
282 my $cstart = $pargs->{insert_comment_start} || "SQLF_INSERT_START";
283 my $cend = $pargs->{insert_comment_end} || "SQLF_INSERT_END";
284
285 # Slurp in the origional file
286 open ( FILE, "<", "$file") or die "Error opening file $file : $!\n";
287 local $/ = undef;
288 my $orig = <FILE>;
289 close(FILE);
290
291 # Insert the new code between the insert comments
292 unless (
293 $orig =~ s/^\s*?$cstart\s*?\n.*?^\s*?$cend\s*?\n/\n$cstart\n$src\n$cend\n/ms
294 ) {
295 warn "No insert done\n";
296 }
297
298 return $orig;
299}
300
3011;
302
303# -------------------------------------------------------------------
304
305=pod
306
307=head1 AUTHOR
308
309Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
310
311=head1 TODO
312
313+ Some tests for the various on exists options (they have been tested
314implicitley through use in a project but need some proper tests).
315
316+ More docs code generation strategies.
317
318+ Better hooks for filename generation.
319
320+ Better integration with TTSchema.
321
322=head1 SEE ALSO
323
324SQL::Translator.
325
326=cut