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