1 package SQL::Translator::Producer::TT::Table;
3 # -------------------------------------------------------------------
4 # $Id: Table.pm,v 1.1 2004-04-01 19:02:39 grommit Exp $
5 # -------------------------------------------------------------------
6 # Copyright (C) 2002-4 SQLFairy Authors
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.
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.
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
21 # -------------------------------------------------------------------
27 SQL::Translator::Producer::TT::Table -
28 Produces output using the Template Toolkit from a SQL schema, per table.
32 # Normal STDOUT version
34 my $translator = SQL::Translator->new(
36 filename => 'foo_schema.sql',
39 tt_table => 'foo_table.tt',
42 print $translator->translate;
44 # To generate a file per table
46 my $translator = SQL::Translator->new(
48 filename => 'foo_schema.sql',
51 tt_table => 'foo_table.tt.html',
53 mk_files_base => "./doc/tables",
54 mk_file_ext => ".html",
55 on_exists => "replace",
59 # ./doc/tables/ now contains the templated tables as $tablename.html
64 Produces schema output using a given Template Tookit template, processing that
65 template for each table in the schema. Optionally allows you to write the result
66 for each table to a seperate file.
68 It needs one additional producer_arg of C<tt_table> which is the file
69 name of the template to use. This template will be passed a template var of
70 C<table>, which is the current C<SQL::Translator::Producer::Table> table we are
71 producing, which you can then use to walk the schema via the methods documented
72 in that module. You also get C<schema> as a shortcut to the
73 C<SQL::Translator::Producer::Schema> for the table and C<translator>, the
74 C<SQL::Translator> object for this parse in case you want to get access to any
75 of the options etc set here.
77 Here's a brief example of what the template could look like:
81 [% FOREACH field = table.get_fields %]
82 [% field.name %] [% field.data_type %]([% field.size %])
85 See F<t/data/template/table.tt> for a more complete example.
87 You can also set any of the options used to initiallize the Template object by
88 adding them to your producer_args. See Template Toolkit docs for details of
91 $translator = SQL::Translator->new(
94 ttfile => 'foo_template.tt',
95 INCLUDE_PATH => '/foo/templates/tt',
100 If you set C<mk_files> and its additional options the producer will write a
101 seperate file for each table in the schema. This is usefull for producing
102 things like HTML documentation where every table gets its own page (you could
103 also use TTSchema producer to add an index page). Its also particulary good
104 for code generation where you want to produce a class file per table.
112 File name of the template to run for each table.
116 Set to true to output a file for each table in the schema (as well as returning
117 the whole lot back to the Translalor and hence STDOUT). The file will be named
118 after the table, with the optional C<mk_files_ext> added and placed in the
119 directory C<mk_files_base>.
123 Extension (without the dot) to add to the filename when using mk_files.
125 =item mk_files_base = DIR
127 Dir to build the table files into when using mk_files. Defaults to the current
132 Set true and if the file needs to written to a directory that doesn't exist,
133 it will be created first.
135 =item on_exists [Default:replace]
137 What to do if we are running with mk_files and a file already exists where we
138 want to write our output. One of "skip", "die", "replace", "insert".
141 B<replace> - Over-write the existing file with the new one, clobbering anything
144 B<skip> - Leave the origional file as it was and don't write the new version
147 B<die> - Die with an existing file error.
149 B<insert> - Insert the generated output into the file bewteen a set of special
150 comments (defined by the following options.) Any code between the comments will
151 be overwritten (ie the results from a previous produce) but the rest of the file
152 is left alone (your custom code).
153 This is particularly usefull for code generation as it allows you to
154 generate schema derived code and then add your own custom code using it to file.
155 Then when the scheam changes you just re-produce and insert the new code.
157 =item insert_comment_start
159 The comment to look for in the file when on_exists is insert. Default is
160 C<SQLF INSERT START>. Must appear on it own line, with only whitespace either
161 side, to be recognised.
163 =item insert_comment_end
165 The end comment to look for in the file when on_exists is insert. Default is
166 C<SQLF INSERT END>. Must appear on it own line, with only whitespace either
167 side, to be recognised.
173 # -------------------------------------------------------------------
177 use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
178 $VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
179 $DEBUG = 0 unless defined $DEBUG;
185 use base qw(Exporter);
186 @EXPORT_OK = qw(produce);
188 use SQL::Translator::Utils 'debug';
194 local $DEBUG = $Translator->debug;
195 my $scma = $Translator->schema;
196 my $pargs = $Translator->producer_args;
197 my $file = $pargs->{'tt_table'} or die "No template file given!";
198 $pargs->{on_exists} ||= "die";
200 debug "Processing template $file\n";
202 my $tt = Template->new(
204 ABSOLUTE => 1, # Set so we can use from the command line sensibly
205 RELATIVE => 1, # Maybe the cmd line code should set it! Security!
206 %$pargs, # Allow any TT opts to be passed in the producer_args
207 ) || die "Failed to initialize Template object: ".Template->error;
209 for my $tbl ( sort {$a->order <=> $b->order} $scma->get_tables ) {
211 $tt->process( $file, {
212 translator => $Translator,
216 or die "Error processing template '$file' for table '".$tbl->name
220 # Write out the file...
221 write_file( table_file($tbl), $outtmp ) if $pargs->{mk_files};
227 # Work out the filename for a given table.
230 my $pargs = $Translator->producer_args;
231 my $root = $pargs->{mk_files_base};
232 my $ext = $pargs->{mk_file_ext};
233 return "$root/$tbl.$ext";
236 # Write the src given to the file given, handling the on_exists arg.
238 my ($file, $src) = @_;
239 my $pargs = $Translator->producer_args;
240 my $root = $pargs->{mk_files_base};
243 if ( $pargs->{on_exists} eq "skip" ) {
244 warn "Skipping existing $file\n";
247 elsif ( $pargs->{on_exists} eq "die" ) {
248 die "File $file already exists.\n";
250 elsif ( $pargs->{on_exists} eq "replace" ) {
251 warn "Replacing $file.\n";
253 elsif ( $pargs->{on_exists} eq "insert" ) {
254 warn "Inserting into $file.\n";
255 $src = insert_code($file, $src);
258 die "Unknown on_exists action: $pargs->{on_exists}\n";
262 warn "Creating $file.\n";
265 my ($dir) = $file =~ m!^(.*)/!; # Want greedy, eveything before the last /
266 if ( $dir and not -d $dir and $pargs->{mk_file_dir} ) { mkpath($dir); }
268 debug "Writing to $file\n";
269 open( FILE, ">$file") or die "Error opening file $file : $!\n";
274 # Reads file and inserts code between the insert comments and returns the new
277 my ($file, $src) = @_;
278 my $pargs = $Translator->producer_args;
279 my $cstart = $pargs->{insert_comment_start} || "SQLF_INSERT_START";
280 my $cend = $pargs->{insert_comment_end} || "SQLF_INSERT_END";
282 # Slurp in the origional file
283 open ( FILE, "<", "$file") or die "Error opening file $file : $!\n";
288 # Insert the new code between the insert comments
290 $orig =~ s/^\s*?$cstart\s*?\n.*?^\s*?$cend\s*?\n/\n$cstart\n$src\n$cend\n/ms
292 warn "No insert done\n";
300 # -------------------------------------------------------------------
306 Mark Addison E<lt>grommit@users.sourceforge.netE<gt>.
310 + Some tests for the various on exists options (they have been tested
311 implicitley through use in a project but need some proper tests).
313 + More docs code generation strategies.
315 + Better hooks for filename generation.
317 + Better integration with TTSchema.