File Coverage

blib/lib/Code/Generator/Perl.pm
Criterion Covered Total %
statement 183 208 87.9
branch 25 36 69.4
condition 18 25 72.0
subroutine 42 44 95.4
pod 7 7 100.0
total 275 320 85.9


line stmt bran cond sub pod time code
1             package Code::Generator::Perl;
2              
3 1     1   25500 use strict;
  1         2  
  1         39  
4 1     1   35 use warnings;
  1         2  
  1         30  
5              
6 1     1   2006 use Data::Dumper;
  1         11663  
  1         77  
7 1     1   8 use Carp;
  1         1  
  1         51  
8 1     1   864 use File::Spec::Functions;
  1         1014  
  1         104  
9 1     1   6 use File::Path qw(make_path);
  1         1  
  1         1646  
10              
11             my %packages_created;
12              
13             our $VERSION = '0.03'; # Don't forget to update the one in POD too!
14              
15             sub new {
16 3     3 1 25 my ($class, %details) = @_;
17              
18 3         7 my $self = {};
19 3   50     17 $self->{outdir} = $details{outdir} || '.';
20 3         9 $self->{base_package} = $details{base_package};
21 3   100     16 $self->{readonly} = $details{readonly} || 0;
22 3         6 $self->{content} = ();
23 3   100     18 $self->{generated_by} = $details{generated_by} || 'a script';
24              
25 3         8 bless ($self, $class);
26 3         11 return $self;
27             }
28              
29             sub _init_use {
30 11     11   14 my ($self) = @_;
31              
32 11         20 my $uses = $self->{use};
33 11 50       23 if (defined $uses) {
34 11         13 foreach my $package (@{$uses}) {
  11         24  
35 20         76 $self->use($package);
36             }
37             } else {
38 0         0 $self->use(qw/strict warnings/);
39             }
40              
41 11 100 100     64 if ($self->{readonly} || $self->{package_readonly}) {
42 3         7 $self->use('Readonly');
43             }
44             }
45              
46             sub use {
47 27     27 1 56 my ($self, @packages) = @_;
48              
49 27         38 map { $self->_add_if_not_yet_used($_) } @packages;
  27         57  
50 27         65 return $self;
51             }
52              
53             sub _add_if_not_yet_used {
54 27     27   33 my ($self, $package) = @_;
55              
56 27 100       32 if (! grep { /$package/ } @{$self->{use}}) {
  57         561  
  27         53  
57 4         6 push @{$self->{use}}, $package;
  4         23  
58             }
59             }
60              
61             sub new_package {
62 11     11 1 58 my ($self, $package_name, %details) = @_;
63              
64 11   50     77 $self->{package} = $package_name
65             || die "new_package: Missing package name";
66 11   33     60 $self->{outdir} = $details{outdir} || $self->{outdir};
67 11   100     50 $self->{use} = $details{use} || [];
68 11         30 $self->{package_generated_by} = $details{generated_by};
69 11 100       28 unshift @{$self->{use}}, 'warnings' if ! defined $details{nowarnings};
  10         32  
70 11 100       30 unshift @{$self->{use}}, 'strict' if ! defined $details{nostrict};
  10         23  
71              
72 11 50       33 if (defined $self->{base_package}) {
73 0         0 $self->{package} = join('::',
74             $self->{base_package},
75             $self->{package});
76             }
77 11         16 $self->{content} = ();
78              
79 11         27 $self->{package_readonly} = $self->{readonly};
80 11 100       27 $self->{package_readonly} = $details{readonly}
81             if defined $details{readonly};
82              
83 11         26 $self->_init_use();
84 11         49 return $self;
85             }
86              
87             sub add_comment {
88 7     7 1 17 my ($self, @comments) = @_;
89              
90 7         28 $self->_add_content("# " . join("\n# ", @comments));
91 7         30 return $self;
92             }
93              
94             sub add {
95 16     16 1 32 my ($self, $name, $value, $options) = @_;
96              
97 16         23 local $Data::Dumper::Indent = 1;
98 16         22 local $Data::Dumper::Purity = 1;
99 16         17 local $Data::Dumper::Deepcopy = 0;
100 16   100     75 local $Data::Dumper::Sortkeys = $options->{sortkeys} || 0;
101              
102 16         26 my $readonly = $self->{readonly};
103 16 50       41 $readonly = $self->{package_readonly}
104             if defined $self->{package_readonly};
105 16 100       40 $readonly = $options->{readonly} if defined $options->{readonly};
106              
107 16         19 local $Data::Dumper::Deepcopy = $readonly;
108              
109 16         115 my $content = Data::Dumper->Dump([$value], [$name]);
110              
111 16 100       957 if ($readonly) {
112 4         36 $self->use('Readonly');
113 4         14 $content =~ s/=/=>/;
114 4         14 $self->_add_content('Readonly::Scalar our ' . $content);
115             } else {
116 12         40 $self->_add_content('our ' . $content);
117             }
118 16         68 return $self;
119             }
120              
121             sub _add_content {
122 23     23   37 my ($self, $content) = @_;
123              
124 23         28 push @{$self->{content}}, $content;
  23         58  
125             }
126              
127             sub _get_line_printer_for {
128 11     11   20 my ($filename) = @_;
129              
130 11 50       1103 open my $file, ">$filename" or die "Could not open $filename\n";
131              
132             return (
133             sub {
134 123     123   158 my ($str) = @_;
135 123   100     387 $str ||= '';
136 123         363 print $file "$str\n";
137             },
138             sub {
139 11     11   535 close $file;
140             },
141 11         79 );
142             }
143              
144             sub _create_directory_or_die {
145 0     0   0 my ($outdir) = @_;
146              
147 0         0 make_path($outdir, { error => \my $errors });
148 0 0       0 if (@$errors) {
149 0         0 for my $diag (@$errors) {
150 0         0 my ($dir, $message) = %$diag;
151             # At most we're creating only one path so dying
152             # immediately is all dandy here. Should be no problem
153             # for immortals like us.
154 0         0 die "Error creating output directory '$outdir': $message";
155             }
156             }
157             }
158              
159             sub _get_outdir_and_filename {
160 11     11   12 my ($self) = @_;
161              
162 11         18 my $outdir = $self->{outdir};
163 11         43 my @dir = split('::', $self->{package});
164 11         21 my $filename = pop @dir;
165              
166 11         38 $outdir = catfile($outdir, @dir);
167 11         57 $filename = catfile($outdir, $filename . '.pm');
168              
169 11         44 return ($outdir, $filename);
170             }
171              
172             sub create {
173 11     11 1 14 my ($self, $options) = @_;
174              
175 11         19 my $package = $self->{package};
176 11 50       28 if ($packages_created{$package}) {
177 0         0 croak join("\n",
178             "ERROR: Package $package has already been written before!",
179             "\tMost likely this is not what you want.",
180             "\tBailing out.",
181             );
182             }
183 11         27 $packages_created{$package} = 1;
184              
185 11         28 my ($outdir, $filename) = $self->_get_outdir_and_filename();
186              
187 11 50       196 if (! -d $outdir) {
188 0         0 _create_directory_or_die($outdir);
189             }
190              
191 11         23 my ($print_line, $done)= _get_line_printer_for($filename);
192 11         41 $print_line->("package $package;");
193 11         28 $print_line->();
194              
195 11         14 map { $print_line->("use $_;") } @{$self->{use}};
  24         57  
  11         26  
196 11 100       12 $print_line->() if (scalar @{$self->{use}});
  11         40  
197              
198 11         26 $print_line->('# You should never edit this file. '
199             . 'Everything in here is automatically');
200 11   66     67 $print_line->('# generated by '
201             . ($self->{package_generated_by}
202             || $self->{generated_by})
203             . '.');
204 11         21 $print_line->();
205              
206 11         15 map { $print_line->($_) } @{$self->{content}};
  23         45  
  11         21  
207              
208 11         18 $print_line->('1;');
209 11         19 $done->();
210 11         28 return $self->_verify_package($package, $filename, $options);
211             }
212              
213             sub _verify_package {
214 11     11   23 my ($self, $package, $filename, $options) = @_;
215              
216 1     1   9 eval "use lib '" . $self->{outdir} . "';";
  1     1   2  
  1     1   7  
  1     1   6  
  1     1   2  
  1     1   6  
  1     1   6  
  1     1   2  
  1     1   5  
  1     1   6  
  1     1   2  
  1         5  
  1         6  
  1         2  
  1         6  
  1         6  
  1         2  
  1         5  
  1         6  
  1         2  
  1         5  
  1         7  
  1         2  
  1         5  
  1         6  
  1         2  
  1         6  
  1         8  
  1         2  
  1         6  
  1         7  
  1         1  
  1         7  
  11         957  
217 1     1   357 eval "use $package;";
  1     1   147  
  1     1   16  
  1     1   424  
  1     1   127  
  1     1   20  
  1     1   309  
  0     1   0  
  0     1   0  
  1     1   430  
  1     1   120  
  1         15  
  1         349  
  1         41  
  1         18  
  1         331  
  1         134  
  1         18  
  1         306  
  0         0  
  0         0  
  1         391  
  1         148  
  1         18  
  1         319  
  0         0  
  0         0  
  1         367  
  0         0  
  0         0  
  1         349  
  0         0  
  0         0  
  11         1750  
218 11 100       1773 if ($@) {
219 5         162 warn "Error while generating $filename:\n\t$@";
220 5         64 return 0;
221             } else {
222 6 50       19 if ($options->{verbose}) {
223 0         0 print "$filename\n";
224             }
225             }
226 6         73 return 1;
227             }
228              
229             sub create_or_die {
230 0     0 1   my ($self, $die_message, $options) = @_;
231              
232 0   0       $die_message ||= '';
233 0 0         if (! $self->create($options)) {
234 0           die "$die_message $!";
235             }
236             }
237              
238             1;
239             __END__