File Coverage

blib/lib/Config/General/Hierarchical/Dump.pm
Criterion Covered Total %
statement 164 165 99.3
branch 84 84 100.0
condition 6 6 100.0
subroutine 14 14 100.0
pod 1 10 10.0
total 269 279 96.4


line stmt bran cond sub pod time code
1             # Config::General::Hierarchical::Dump.pm - Hierarchical Generic Config Dumper Module
2              
3             package Config::General::Hierarchical::Dump;
4              
5             $Config::General::Hierarchical::Dump::VERSION = 0.07;
6              
7 1     1   1164 use strict;
  1         2  
  1         125  
8 1     1   6 use warnings;
  1         2  
  1         38  
9              
10 1     1   896 use Config::General::Hierarchical;
  1         4  
  1         5  
11              
12             sub deep_dump {
13 26     26 0 46 my ( $names, $cfg, $errors ) = @_;
14              
15 26         32 my @return;
16              
17 26         45 foreach my $key ( sort keys %{ $cfg->value } ) {
  26         79  
18 70         392 my $file = $cfg->value->{$key}->file;
19 70         697 my $name = join( '->', @$names, $key );
20 70         83 my $value = eval { $cfg->get($key); };
  70         237  
21              
22 70 100       1276 if ($@) {
    100          
23 9         30 my @tmp = ( $name, 'error;', $file );
24              
25 9         14 push @return, \@tmp;
26 9         100 push @$errors, \@tmp;
27             }
28             elsif ( defined $value ) {
29 57 100       69 if ( eval { $value->isa('Config::General::Hierarchical') } ) {
  57         506  
30 12         25 push @$names, $key;
31 12         46 push @return, deep_dump( $names, $value, $errors );
32 12         33 pop @$names;
33             }
34             else {
35 45         104 push @return, translate_value( $name, $value, $file );
36             }
37             }
38             else {
39 4         15 push @return, [ $name, 'undef;', $file ];
40             }
41             }
42              
43 26         103 return @return;
44             }
45              
46             sub do_all {
47 23     23 0 28323 my ( $class, $file_name, $params_array, $parser_class ) = @_;
48              
49 23 100       104 return () unless $file_name;
50              
51 22         52 my ( $check, $file, $fixed_length, $help, $json );
52 0         0 my ( $sfile, $stfile );
53 22         67 my $error = '';
54              
55 22         112 parse_options( $params_array, \$error, \$check, \$file, \$fixed_length,
56             \$help, \$json );
57              
58 22 100       3450 return <
59             $error Usage: $0
60             Dumps the Config::General::Hierarchical configuration file itself
61              
62             -c, --check if present, prints only the variables that do
63             not respect syntax constraint
64             -f, --file shows in which file variables are defined
65             -l, --fixed-length formats output as fixed length fields
66             -h, --help prints this help and exits
67             -j, --json prints output as json
68             EOF
69              
70 17 100       47 if ($parser_class) {
71 1         77 eval "require $parser_class";
72             }
73             else {
74 16         147 $parser_class = $class->parser;
75             }
76              
77 17         29 my ( $cfg, @errors );
78              
79 17         28 eval { $cfg = $parser_class->new( file => $file_name ); };
  17         128  
80              
81 17 100       85 return "Parsing error: $@\n" if $@;
82              
83 16 100       84 return json_dump($cfg) if $json;
84              
85 14         62 my @output = deep_dump( [], $cfg, \@errors );
86 14 100 100     83 my $output = ( $check && scalar @errors ) ? \@errors : \@output;
87 14         43 my $format = make_format( $fixed_length, $file, $output );
88 14         55 my $base_dir = find_base_dir( $cfg->opt->files );
89              
90 14         30 my @files;
91             my @return;
92              
93 14 100       33 if ($file) {
94 5         11 my $base_dir_len = 1 + length $base_dir;
95              
96 5         14 push @return, "Configuration files base dir: $base_dir/\n";
97              
98 5         10 @files = map substr( $_, $base_dir_len ), @{ $cfg->opt->files };
  5         16  
99              
100 5 100       60 if ( scalar @files > 1 ) {
101              
102 1         10 push @return, "Files inheritance structure:\n";
103 1         5 push @return, dump_struct( $cfg->opt->struct->{0}, \@files );
104             }
105             }
106              
107 14 100       254 push @return,
108             map( ref $_
109             ? sprintf( $format, $_->[0], $_->[1], $files[ $_->[2] ] )
110             : $_,
111             @$output );
112              
113 14         259 return @return;
114             }
115              
116             sub dump_struct {
117 2     2 0 12 my ( $struct, $files, $key, $lvl ) = @_;
118              
119 2   100     11 $key ||= 0;
120 2   100     7 $lvl ||= 1;
121              
122 2         14 my @ret = ( ( ' ' x $lvl ) . $files->[$key] . "\n" );
123              
124 2         16 push @ret, map dump_struct( $struct->{$_}, $files, $_, $lvl + 1 ),
125             keys %$struct;
126              
127 2         7 return @ret;
128             }
129              
130             sub find_base_dir {
131 14     14 0 120 my ($files) = @_;
132              
133 14         89 my @mcp = split '/', $files->[0];
134 14         28 my $last = scalar @$files;
135              
136 14         20 pop @mcp;
137              
138 14         46 for ( my $i = 1 ; $i < $last ; ++$i ) {
139 4         22 my @this = split '/', $files->[$i];
140              
141 4         19 for ( my $j = 0 ; $j < scalar @mcp ; ++$j ) {
142 24 100       73 if ( $mcp[$j] ne $this[$j] ) {
143 4         35 splice @mcp, $j;
144             }
145             }
146             }
147              
148 14         64 return join '/', @mcp;
149             }
150              
151             sub import {
152 2     2   318 my ( $class, @pars ) = @_;
153              
154 2 100       19 return if caller ne 'main';
155              
156 1         6 print join '', $class->do_all( $0, \@ARGV, $pars[0] );
157              
158 1         274 exit;
159             }
160              
161             sub json_dump {
162 4     4 0 8 my ($cfg) = @_;
163              
164 4         7 my $return = '{';
165              
166 4         6 foreach my $key ( sort keys %{ $cfg->value } ) {
  4         13  
167 14         61 $return .= "\"$key\":";
168              
169 14         19 my $value = eval { $cfg->get($key); };
  14         806  
170              
171 14 100       362 if ($@) {
    100          
172 4         15 $return .= '"error",';
173             }
174             elsif ( defined $value ) {
175 8 100       12 if ( eval { $value->isa('Config::General::Hierarchical') } ) {
  8         102  
176 2         15 $return .= json_dump($value) . ',';
177             }
178             else {
179 6         16 $return .= translate_json($value);
180             }
181             }
182             else {
183 2         6 $return .= 'null,';
184             }
185             }
186              
187 4         11 chop $return;
188              
189 4         25 return $return . '}';
190             }
191              
192             sub make_format {
193 14     14 0 22 my ( $fixed_length, $file, $output ) = @_;
194              
195 14         38 my $format = "\%s = \%s\n";
196              
197 14 100       34 if ($fixed_length) {
198 7         13 my $maxlen = 0;
199 7         14 my $len;
200              
201 7         22 foreach (@$output) {
202 31 100       69 next unless ref $_;
203              
204 28         42 $len = length $_->[0];
205              
206 28 100       73 $maxlen = $len if $len > $maxlen;
207             }
208              
209 7         23 $format = '%-' . $maxlen . "s = %";
210 7         13 $maxlen = 0;
211              
212 7         15 foreach (@$output) {
213 31 100       73 next unless ref $_;
214              
215 28         31 $len = length $_->[1];
216              
217 28 100       72 $maxlen = $len if $len > $maxlen;
218             }
219              
220 7 100       19 if ($file) {
221 3         8 $format .= '-' . $maxlen . "s \%s\n";
222             }
223             else {
224 4         1442 $format .= "s\n";
225             }
226             }
227             else {
228 7 100       27 $format = "\%s = \%s \%s\n" if $file;
229             }
230              
231 14         44 return $format;
232             }
233              
234             sub parse_options {
235 22     22 0 41 my ( $params_array, $error, $check, $file, $fixed_length, $help, $json ) =
236             @_;
237              
238 22         59 foreach my $param (@$params_array) {
239 19 100       79 if ( substr( $param, 0, 1 ) ne '-' ) {
240 1         2 $$help = 1;
241 1         3 $$error = "Unknown options '$param'\n\n";
242 1         6 return;
243             }
244              
245 18 100       80 if ( substr( $param, 0, 2 ) eq '--' ) {
246 7 100       44 if ( $param eq '--check' ) {
    100          
    100          
    100          
    100          
247 1         5 $$check = 1;
248             }
249             elsif ( $param eq '--file' ) {
250 2         5 $$file = 1;
251             }
252             elsif ( $param eq '--fixed-length' ) {
253 1         3 $$fixed_length = 1;
254             }
255             elsif ( $param eq '--help' ) {
256 1         5 $$help = 1;
257             }
258             elsif ( $param eq '--json' ) {
259 1         4 $$json = 1;
260             }
261             else {
262 1         6 $$help = 1;
263 1         4 $$error = "Unknown options '$param'\n\n";
264 1         6 return;
265             }
266             }
267             else {
268 11         50 for ( my $i = 1 ; $i < length $param ; ++$i ) {
269 14         32 my $p = substr $param, $i, 1;
270              
271 14 100       158 if ( $p eq 'c' ) {
    100          
    100          
    100          
    100          
272 2         8 $$check = 1;
273             }
274             elsif ( $p eq 'f' ) {
275 3         13 $$file = 1;
276             }
277             elsif ( $p eq 'h' ) {
278 1         6 $$help = 1;
279             }
280             elsif ( $p eq 'j' ) {
281 1         6 $$json = 1;
282             }
283             elsif ( $p eq 'l' ) {
284 6         34 $$fixed_length = 1;
285             }
286             else {
287 1         3 $$help = 1;
288 1         3 $$error = "Unknown options '-$p'\n\n";
289 1         3 return;
290             }
291             }
292             }
293             }
294             }
295              
296 9     9 1 21 sub parser { return 'Config::General::Hierarchical'; }
297              
298             sub translate_json {
299 6     6 0 11 my ($value) = @_;
300              
301 6 100       84 unless ( ref $value ) {
302 2         6 $value =~ s/\n/\\n/g;
303              
304 2         10 return "\"$value\",";
305             }
306              
307 4         9 my $ret = '[';
308              
309 4         16 foreach my $val (@$value) {
310 8         13 $val =~ s/\n/\\n/g;
311 8         20 $ret .= "\"$val\",";
312             }
313              
314 4         8 chop $ret;
315              
316 4         15 return $ret . '],';
317             }
318              
319             sub translate_value {
320 45     45 0 80 my ( $name, $value, $file ) = @_;
321              
322 45 100       118 unless ( ref $value ) {
323 36 100       281 return [ $name, "'$value';", $file ] if $value !~ /\n/;
324              
325 2         7 my $return = [ $name, '<
326              
327 2 100       15 return ( $return, $value . "EOF\n" ) if $value =~ /\n$/;
328              
329 1         5 return ( $return, $value . "//--new line added\nEOF\n" );
330             }
331              
332 9         12 my @ret;
333 9         13 my $simple = 1;
334              
335 9         20 foreach my $val (@$value) {
336 18 100       58 $simple = 0 if $val =~ /\n/;
337             }
338              
339 9 100       178 return [ $name, "( '" . join( "', '", @$value ) . "' );", $file ]
340             if $simple;
341              
342 1         14 return ( [ $name, '*;', $file ],
343             "* = ( '" . join( "', '", @$value ) . "' );\n" );
344             }
345              
346             1;
347              
348             __END__