File Coverage

blib/lib/PPrint.pm
Criterion Covered Total %
statement 114 160 71.2
branch 34 48 70.8
condition 15 27 55.5
subroutine 20 29 68.9
pod 8 14 57.1
total 191 278 68.7


line stmt bran cond sub pod time code
1             package PPrint;
2             require 5.005_62;
3 1     1   1824 use strict;
  1         2  
  1         26  
4 1     1   4 use warnings;
  1         1  
  1         22  
5 1     1   6 use Carp;
  1         4  
  1         89  
6 1     1   860 use Data::Dumper; # need this for the A directive
  1         9835  
  1         86  
7              
8             BEGIN {
9 1     1   8 use Exporter ();
  1         1  
  1         81  
10 1     1   2 our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
11 1         2 our $VERSION = "0.1";
12 1         16 @ISA = qw( Exporter );
13 1         2 @EXPORT = qw( &pprint );
14 1         2 %EXPORT_TAGS = qw( );
15 1         7618 @EXPORT_OK = qw( );
16             }
17              
18             sub tilde {
19 3     3 0 5 my @params = @{ $_[0] };
  3         7  
20 3   100     12 my $repeat = $params[0] || 1;
21 3     3   20 return sub { '~' x $repeat };
  3         20  
22             }
23              
24             sub R {
25 4     4 1 5 my ($params, $flags) = @_;
26 4   100     18 my $radix = $params->[0] || 10;
27 4 50       11 carp "Nonsense radix: $radix" if $radix < 1;
28 4   100     16 my $mincol = $params->[1] || 0;
29 4 50       9 carp "Invalid minimum numbers of columns: $mincol" if $mincol < 0;
30 4 100       11 my $padchar = defined $params->[2] ? $params->[2] : " ";
31 4   100     27 my $commachar = $params->[3] || ',';
32 4   100     12 my $commainterval = $params->[4] || 3;
33              
34             return sub {
35 4     4   5 my @args = @{ $_[0] };
  4         8  
36 4         5 my $num = shift @args;
37 4         12 my $str = toStringRadix(abs $num, $radix);
38 4 100       17 if ($flags->{":"}) {
39             # add in commas
40 1 50       14 $str = reverse join $commachar, grep { defined $_ && $_ ne '' } split /(.{$commainterval})/, reverse $str;
  4         19  
41             }
42 4 100       11 $str = "-" . $str if $num < 0;
43 4 100 100     20 $str = "+" . $str if ($num > 0) && (defined($flags->{";"}));
44 4 100       10 if (length($str) < $mincol) {
45 2         7 my $padding = $padchar x ($mincol - length($str));
46 2 50       4 if ($flags->{"!"}) {
47 0         0 $str = $str . $padding;
48             } else {
49 2         5 $str = $padding . $str;
50             }
51             }
52 4         21 return $str;
53             }
54 4         33 }
55              
56             sub D {
57 0     0 1 0 my ($params, $flags) = @_;
58 0         0 unshift @{ $params }, 10;
  0         0  
59 0         0 return R(@_);
60             }
61              
62             sub O {
63 0     0 1 0 my ($params, $flags) = @_;
64 0         0 unshift @{ $params }, 8;
  0         0  
65 0         0 return R(@_);
66             }
67              
68             sub X {
69 0     0 1 0 my ($params, $flags) = @_;
70 0         0 unshift @{ $params }, 16;
  0         0  
71 0         0 return R(@_);
72             }
73              
74             sub B {
75 0     0 1 0 my ($params, $flags) = @_;
76 0         0 unshift @{ $params }, 2;
  0         0  
77 0         0 return R(@_);
78             }
79              
80             sub S {
81 0     0 1 0 my ($params, $flags) = @_;
82 0     0   0 return sub { sprintf("\%s", shift @{ $_[0] } ); };
  0         0  
  0         0  
83             }
84              
85             sub A {
86 0     0 1 0 my ($params, $flags) = @_;
87 0         0 my ($indent_style, $purity, $useqq, $terse, $deepcopy,
88 0         0 $quotekeys, $max_depth) = @{ $params };
89 0 0       0 $indent_style = 2 unless defined $indent_style;
90 0   0     0 $purity ||= 0;
91 0   0     0 $useqq ||= 0;
92 0   0     0 $terse ||= 0;
93 0   0     0 $deepcopy ||= 0;
94 0   0     0 $quotekeys ||= 0;
95 0   0     0 $max_depth ||= 0;
96              
97 0         0 my $dumper = Data::Dumper->new([])
98             ->Indent($indent_style)
99             ->Purity($purity)
100             ->Useqq($useqq)
101             ->Terse($terse)
102             ->Deepcopy($deepcopy)
103             ->Quotekeys($quotekeys)
104             ->Maxdepth($max_depth);
105              
106             return sub {
107 0     0   0 $dumper->Values([ shift @{ $_[0] } ]);
  0         0  
108 0         0 $dumper->Dump;
109             }
110 0         0 }
111              
112             sub n {
113 3     3 1 5 my ($params, $flags) = @_;
114 3   100     12 my $repeats = $params->[0] || 1;
115 3         5 my $type = $params->[1];
116 3         5 my $new_line = "\n";
117 3 100       7 if ($type) {
118 1 50       8 if ($type eq 'm') {
    50          
    50          
119 0         0 $new_line = chr(0x0D);
120             } elsif ($type eq 'u') {
121 0         0 $new_line = chr(0x0A);
122             } elsif ($type eq 'd') {
123 1         2 $new_line = chr(0x0D) . chr(0x0A);
124             }
125             }
126 3     3   22 return sub { "$new_line" x $repeats; };
  3         39  
127             }
128              
129             sub J {
130 3     3 0 6 my ($params, $flags) = @_;
131 3         4 my ($join_char, $pre_char, $post_char) = @{ $params };
  3         7  
132 3 100       19 $join_char = ' ' unless defined $join_char;
133 3 100       8 $pre_char = '' unless defined $pre_char;
134 3 100       9 $post_char = '' unless defined $post_char;
135             return sub {
136 3     3   4 my @to_join = @{ shift @{ $_[0] } };
  3         4  
  3         11  
137 3         22 return $pre_char . join($join_char, @to_join) . $post_char;
138             }
139 3         25 }
140              
141             ######################################################################
142             # utilities
143              
144             # take a positive integer, return it's string representation in radix n
145             sub toStringRadix {
146 4     4 0 7 my ($num, $radix) = @_;
147 4 50       9 if ($radix == 0) {
148 0         0 carp "0 is a sensless value for a radix, what are you thinking?";
149 0         0 return;
150             }
151 4 50       11 if ($radix < 0) {
152 0         0 carp "what am i supposed to do with a negative radix?";
153 0         0 return;
154             }
155 4         44 my @alphabet = ( "0" .. "9", "a" .. "z" );
156 4         6 my $string = "";
157 4         11 while ($num != 0) {
158 16         17 my $rem = $num % $radix;
159 16         22 $num = int($num/$radix);
160 16         43 $string = $alphabet[$rem] . $string;
161             }
162 4         17 return $string;
163             }
164              
165             ######################################################################
166             # directive table
167              
168             my %standard_directives = ( 'n' => \&n,
169             '~' => \&tilde,
170             'r' => \&R,
171             'd' => \&D,
172             'o' => \&O,
173             'x' => \&X,
174             'b' => \&B,
175             'a' => \&A,
176             'j' => \&J,
177             );
178              
179             our %directives = %standard_directives;
180              
181             #####################################################################
182             # do it!
183              
184             my $flags_class = "[:!@|?;]";
185              
186             # build_directive takes a dirctive string as an arg and returns a sub
187             # which takes the argument list as an arg
188             sub build_directive {
189 13     13 0 20 my $directive_string = shift;
190             # the type of directive is the last char in the string
191 13         24 my $directive_type = substr ($directive_string, -1);
192             # remove leading '~' and last char (directive type)
193 13         17 $directive_string = substr ($directive_string, 1);
194 13         20 $directive_string = substr ($directive_string, 0, -1);
195 13         12 my %flags;
196 13 100       77 if ($directive_string =~ s/((?
197 1         5 %flags = map { $_ => 1 } split //, $2;
  2         7  
198             }
199 13         43 my @params = map { s/^'//; $_ }
  17         31  
  17         40  
200             split /(?
201 13 100       29 if (grep { $_ eq "v" } @params) {
  17         38  
202             # v arg, we have to build the directive function at ever
203             # invocation:
204             return sub {
205 1     1   2 my @args = @{ shift() };
  1         3  
206             @params = map {
207 1 50       2 if ($_ eq "v") {
  1         4  
208 1         3 shift(@args);
209             } else {
210 0         0 $_;
211             }
212             } @params;
213 1         3 $directives{$directive_type}->(\@params, \%flags)->(@args);
214             }
215 1         15 } else {
216 12         37 return $directives{$directive_type}->(\@params, \%flags);
217             }
218             }
219              
220             # we go through $string and build up a list of subs to call
221             sub compile_control_string {
222 13     13 0 52 my $directive_class = join('', keys %directives);
223 13         133 my $directive_regexp =
224             qr/(~ # start with a '~'
225             (?:(?:[,0-9]|'.)*?) # followed by a sequence of nu\mbers or quoted chars or co\m\mas
226             $flags_class* # then the flags
227             (?
228             /x;
229 13         21 my $control = shift;
230             my @pieces =
231             map {
232             # build up the sub
233 13 50       81 if (/$directive_regexp/) {
  26         51  
234 13         24 build_directive($_);
235             } else {
236 0     0   0 sub { $_ };
  0         0  
237             }
238 13         98 } grep { $_ } split $directive_regexp, $control;
239             return sub {
240 13     13   22 my @args = @_;
241 13         21 join '', map { $_->(\@args) } @pieces;
  13         25  
242             }
243 13         95 }
244              
245             sub pprint {
246 13     13 0 679 my ($control, @args) = @_;
247 13 50       34 if (ref $control eq 'CODE') {
248 0         0 return $control->(@args);
249             } else {
250 13         25 return compile_control_string($control)->(@args);
251             }
252             }
253              
254             1;
255             __END__;