File Coverage

blib/lib/Text/sprintfn.pm
Criterion Covered Total %
statement 37 38 97.3
branch 14 14 100.0
condition n/a
subroutine 4 5 80.0
pod 2 2 100.0
total 57 59 96.6


line stmt bran cond sub pod time code
1             ## no critic: Modules::ProhibitAutomaticExportation
2              
3             package Text::sprintfn;
4              
5 1     1   62945 use 5.010001;
  1         12  
6 1     1   5 use strict;
  1         2  
  1         19  
7 1     1   4 use warnings;
  1         2  
  1         647  
8              
9             require Exporter;
10             our @ISA = qw(Exporter);
11             our @EXPORT = qw(sprintfn printfn);
12              
13             our $VERSION = '0.090'; # VERSION
14              
15             our $distance = 10;
16              
17             my $re1 = qr/[^)]+/s;
18             my $re2 = qr{(?
19             %
20             (? \d+\$ | \((?$re1)\)\$?)?
21             (? [ +0#-]+)?
22             (? \*?[v])?
23             (? -?\d+ |
24             \*\d+\$? |
25             \((?$re1)\))?
26             (?\.?)
27             (?
28             (?: \d+ | \* |
29             \((?$re1)\) ) ) ?
30             (? [%csduoxefgXEGbBpniDUOF])
31             )}x;
32             our $regex = qr{($re2|%|[^%]+)}s;
33              
34             # faster version, without using named capture
35             if (1) {
36             $regex = qr{( #all=1
37             ( #fmt=2
38             %
39             (#pi=3
40             \d+\$ | \(
41             (#npi=4
42             [^)]+)\)\$?)?
43             (#flags=5
44             [ +0#-]+)?
45             (#vflag=6
46             \*?[v])?
47             (#width=7
48             -?\d+ |
49             \*\d+\$? |
50             \((#nwidth=8
51             [^)]+)\))?
52             (#dot=9
53             \.?)
54             (#prec=10
55             (?: \d+ | \* |
56             \((#nprec=11
57             [^)]+)\) ) ) ?
58             (#conv=12
59             [%csduoxefgXEGbBpniDUOF])
60             ) | % | [^%]+
61             )}xs;
62             }
63              
64             sub sprintfn {
65 29     29 1 14510 my ($format, @args) = @_;
66              
67 29         47 my $hash;
68 29 100       85 if (ref($args[0]) eq 'HASH') {
69 14         26 $hash = shift(@args);
70             }
71 29 100       198 return sprintf($format, @args) if !$hash;
72              
73 14         19 my %indexes; # key = $hash key, value = index for @args
74 14         37 push @args, (undef) x $distance;
75              
76 14         96 $format =~ s{$regex}{
77 56         223 my ($all, $fmt, $pi, $npi, $flags,
78             $vflag, $width, $nwidth, $dot, $prec,
79             $nprec, $conv) =
80             ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
81              
82 56         70 my $res;
83 56 100       96 if ($fmt) {
84              
85 21 100       42 if (defined $npi) {
86 14         65 my $i = $indexes{$npi};
87 14 100       32 if (!$i) {
88 13         20 $i = @args + 1;
89 13         24 push @args, $hash->{$npi};
90 13         23 $indexes{$npi} = $i;
91             }
92 14         26 $pi = "${i}\$";
93             }
94              
95 21 100       39 if (defined $nwidth) {
96 5         8 $width = $hash->{$nwidth};
97             }
98              
99 21 100       36 if (defined $nprec) {
100 5         8 $prec = $hash->{$nprec};
101             }
102              
103             $res = join("",
104 21         38 grep {defined} (
  168         276  
105             "%",
106             $pi, $flags, $vflag,
107             $width, $dot, $prec, $conv)
108             );
109             } else {
110 35         51 my $i = @args + 1;
111 35         63 push @args, $all;
112 35         72 $res = "\%${i}\$s";
113             }
114 56         248 $res;
115             }xego;
116              
117             # DEBUG
118             #use Data::Dump; dd [$format, @args];
119              
120 14         143 sprintf $format, @args;
121             }
122              
123             sub printfn {
124 0     0 1   print sprintfn @_;
125             }
126              
127             1;
128             # ABSTRACT: Drop-in replacement for sprintf(), with named parameter support
129              
130             __END__