File Coverage

blib/lib/Localizer/Style/Gettext.pm
Criterion Covered Total %
statement 66 66 100.0
branch 25 26 96.1
condition n/a
subroutine 10 10 100.0
pod 0 2 0.0
total 101 104 97.1


line stmt bran cond sub pod time code
1             package Localizer::Style::Gettext;
2 7     7   58775 use strict;
  7         21  
  7         434  
3 6     6   27 use warnings;
  6         8  
  6         311  
4 6     6   43 use utf8;
  6         10  
  6         166  
5 6     6   132 use 5.010_001;
  6         16  
6              
7 6     6   195 use B;
  6         15  
  6         199  
8 6     6   193 use Carp ();
  6         14  
  6         3055  
9              
10 7     7 0 11297 sub new { bless {}, shift }
11              
12             sub compile {
13 26     25 0 1493 my ($self, $msgid, $fmt, $functions) = @_;
14 26         52 my $code = $self->_compile($msgid, $fmt, $functions);
15 25         211 return $code;
16             }
17              
18             sub _compile {
19 25     25   45 my ($self, $msgid, $str, $functions) = @_;
20              
21 25 100       96 return \$str unless $str =~ /%/;
22              
23 13         20 my @code;
24             my @bind;
25 13         83 while ($str =~ m/
26             (.*?)
27             (?:
28             ([\\%]%)
29             |
30             %(?:
31             ([A-Za-z#*]\w*)\(([^\)]*)\)
32             |
33             ([1-9]\d*|\*)
34             )
35             |
36             $
37             )
38             /gsx
39             ) {
40 34 100       73 if ($1) { # Raw string
41 15         25 my $text = $1;
42 15 100       38 if ($text !~ m/[^\x20-\x7E]/s) { # ASCII very safe chars
43 12         18 $text =~ s/\\/\\\\/g;
44 12         46 push @code, B::perlstring($text) . ',';
45             } else {
46             # For example, `(eval "sub { qq{% usar\x{e1}n}}")->()` drops UTF-8 flag.
47             # This code is the workaround for this issue.
48 3         15 push @code, sprintf(q{$bind[%d],}, 0+@bind);
49 3         8 push @bind, $text;
50             }
51             }
52 34 100       127 if ($2) { # \% %%
    100          
    100          
53 2         4 my $text = $2;
54 2         4 $text =~ s/\\/\\\\\\\\/g;
55 2         10 push @code, "'" . $text . "',";
56             }
57             elsif ($3) {
58 6         8 my $function_name = $3;
59 6 100       17 if ($function_name eq '*') {
    100          
60 1         2 $function_name = 'quant';
61             }
62             elsif ($function_name eq '#') {
63 1         16 $function_name = 'numf';
64             }
65              
66 6 100       12 unless (exists $functions->{$function_name}) {
67 1         179 Carp::confess("Language resource compilation error. Unknown function: '${function_name}'");
68             }
69              
70 5         10 my $code = q!$functions->{'! . $function_name . q!'}->(!;
71 5         15 for my $arg (split(/,/, $4)) {
72 7 100       23 if (my ($num) = $arg =~ /%(\d+)/) {
73 5         14 $code .= '$_[' . $num . '], ';
74             }
75             else {
76 2         5 $code .= "'" . $arg . "', ";
77             }
78             }
79 5         8 $code .= '), ';
80 5         18 push @code, $code;
81             }
82             elsif ($5) {
83 9         12 my $arg = $5;
84              
85 9         12 my $var = '';
86 9 100       16 if ($arg eq '*') {
87 2         2 $var = '@_[1 .. $#_],';
88             }
89             else {
90 7         23 $var = '$_[' . $arg . '],';
91             }
92 9         41 push @code, $var;
93             }
94             }
95              
96 12 100       29 if (@code > 1) { # most cases, presumably!
97 10         17 unshift @code, "join '',\n";
98             }
99 12         28 unshift @code, qq!#line 1 "${msgid}"\n!;
100 12         21 unshift @code, "use strict; sub {\n";
101 12         19 push @code, "}\n";
102              
103 4     4   152 my $sub = eval(join '', @code); ## no critic.
  4         10  
  4         490  
  12         701  
104 12 50       148 die "Language resource compilation error: $@ while evalling" . join('', @code) if $@; # Should be impossible.
105 12         39 return $sub;
106             }
107              
108             1;
109             __END__