File Coverage

blib/lib/SQL/Translator/Producer/TT/Base.pm
Criterion Covered Total %
statement 61 70 87.1
branch 8 16 50.0
condition 3 7 42.8
subroutine 17 20 85.0
pod 10 11 90.9
total 99 124 79.8


line stmt bran cond sub pod time code
1             package SQL::Translator::Producer::TT::Base;
2              
3             =pod
4              
5             =head1 NAME
6              
7             SQL::Translator::Producer::TT::Base - TT (Template Toolkit) based Producer base
8             class.
9              
10             =cut
11              
12 1     1   64657 use strict;
  1         3  
  1         42  
13 1     1   6 use warnings;
  1         1  
  1         109  
14              
15             our @EXPORT_OK;
16             our $VERSION = '1.66';
17              
18 1     1   5 use Template;
  1         2  
  1         42  
19 1     1   5 use Data::Dumper;
  1         1  
  1         81  
20 1     1   7 use IO::Handle;
  1         2  
  1         37  
21 1     1   5 use Exporter;
  1         1  
  1         26  
22 1     1   4 use base qw(Exporter);
  1         1  
  1         189  
23             @EXPORT_OK = qw(produce);
24              
25 1     1   5 use SQL::Translator::Utils 'debug';
  1         2  
  1         677  
26              
27             # Hack to convert the produce call into an object. ALL sub-classes need todo
28             # this so that the correct class gets created.
29             sub produce {
30 0     0 0 0 return __PACKAGE__->new(translator => shift)->run;
31             }
32              
33             sub new {
34 1     1 1 20 my $proto = shift;
35 1   33     5 my $class = ref $proto || $proto;
36 1         4 my %args = @_;
37              
38 1         3 my $me = bless {}, $class;
39 1   50     33 $me->{translator} = delete $args{translator} || die "Need a translator.";
40              
41 1         10 return $me;
42             }
43              
44 2     2 1 57 sub translator { shift->{translator}; }
45 1     1 1 22 sub schema { shift->{translator}->schema(@_); }
46              
47             # Util args access method.
48             # No args - Return hashref (the actual hash in Translator) or hash of args.
49             # 1 arg - Return that named args value.
50             # Args - List of names. Return values of the given arg names in list context
51             # or return as hashref in scalar context. Any names given that don't
52             # exist in the args are returned as undef.
53             sub args {
54 2     2 1 2 my $me = shift;
55              
56             # No args
57 2 100       6 unless (@_) {
58             return wantarray
59 0         0 ? %{ $me->{translator}->producer_args }
60 1 50       17 : $me->{translator}->producer_args;
61             }
62              
63             # 1 arg. Return the value whatever the context.
64 1 50       15 return $me->{translator}->producer_args->{ $_[0] } if @_ == 1;
65              
66             # More args so return values list or hash ref
67 0         0 my %args = %{ $me->{translator}->producer_args };
  0         0  
68 0 0       0 return wantarray ? @args{@_} : { map { ($_ => $args{$_}) } @_ };
  0         0  
69             }
70              
71             # Run the produce and return the result.
72             sub run {
73 1     1 1 3 my $me = shift;
74 1         29 my $scma = $me->schema;
75 1         9 my %args = %{ $me->args };
  1         5  
76 1 50       5 my $tmpl = $me->tt_schema or die "No template!";
77              
78 1         8 debug "Processing template $tmpl\n";
79 1         2 my $out;
80 1   50     5 my $tt = Template->new(
81              
82             #DEBUG => $me->translator->debug,
83             ABSOLUTE => 1, # Set so we can use from the command line sensibly
84             RELATIVE => 1, # Maybe the cmd line code should set it! Security!
85             $me->tt_config, # Hook for sub-classes to add config
86             %args, # Allow any TT opts to be passed in the producer_args
87             ) || die "Failed to initialize Template object: " . Template->error;
88              
89 1 50       21224 $tt->process(
90             $tmpl,
91             {
92             $me->tt_default_vars,
93             $me->tt_vars, # Sub-class hook for adding vars
94             },
95             \$out
96             ) or die "Error processing template '$tmpl': " . $tt->error;
97              
98 1         230 return $out;
99             }
100              
101             # Sub class hooks
102             #-----------------------------------------------------------------------------
103              
104 0     0 1 0 sub tt_config { () }
105              
106             sub tt_schema {
107 1     1 1 2 my $me = shift;
108 1         2 my $class = ref $me;
109              
110 1         4 my $file = $me->args("ttfile");
111 1 50       4 return $file if $file;
112              
113 1     1   7 no strict 'refs';
  1         2  
  1         211  
114 1         2 my $ref = *{"$class\:\:DATA"}{IO};
  1         6  
115 1 50       15 if ($ref->opened) {
116 1         19 local $/ = undef; # Slurp mode
117 1         63 return \<$ref>;
118             }
119              
120 0         0 undef;
121             }
122              
123             sub tt_default_vars {
124 1     1 1 3 my $me = shift;
125             return (
126 1         7 translator => $me->translator,
127             schema => $me->pre_process_schema($me->translator->schema),
128             );
129             }
130              
131 1     1 1 20 sub pre_process_schema { $_[1] }
132              
133 0     0 1   sub tt_vars { () }
134              
135             1;
136              
137             =pod
138              
139             =head1 SYNOPSIS
140              
141             # Create a producer using a template in the __DATA__ section.
142             package SQL::Translator::Producer::Foo;
143              
144             use base qw/SQL::Translator::Producer::TT::Base/;
145              
146             # Convert produce call into a method call on our new class
147             sub produce { return __PACKAGE__->new( translator => shift )->run; };
148              
149             # Configure the Template object.
150             sub tt_config { ( INTERPOLATE => 1 ); }
151              
152             # Extra vars to add to the template
153             sub tt_vars { ( foo => "bar" ); }
154              
155             # Put template in DATA section (or use file with ttfile producer arg)
156             __DATA__
157             Schema
158              
159             Database: [% schema.database %]
160             Foo: $foo
161             ...
162              
163             =head1 DESCRIPTION
164              
165             A base class producer designed to be sub-classed to create new TT based
166             producers cheaply - by simply giving the template to use and sprinkling in some
167             extra template variables and config.
168              
169             You can find an introduction to this module in L.
170              
171             The 1st thing the module does is convert the produce sub routine call we get
172             from SQL::Translator into a method call on an object, which we can then
173             sub-class. This is done with the following code which needs to appear in B
174             sub classes.
175              
176             # Convert produce call into an object method call
177             sub produce { return __PACKAGE__->new( translator => shift )->run; };
178              
179             See L below for details.
180              
181             The upshot of this is we can make new template producers by sub classing this
182             base class, adding the above snippet and a template.
183             The module also provides a number of hooks into the templating process,
184             see L for details.
185              
186             See the L above for an example of creating a simple producer using
187             a single template stored in the producers DATA section.
188              
189             =head1 SUB CLASS HOOKS
190              
191             Sub-classes can override these methods to control the templating by giving
192             the template source, adding variables and giving config to the Tempate object.
193              
194             =head2 tt_config
195              
196             sub tt_config { ( INTERPOLATE => 1 ); }
197              
198             Return hash of Template config to add to that given to the L