File Coverage

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


line stmt bran cond sub pod time code
1             package Localizer::Style::Gettext;
2 7     7   22390 use strict;
  7         23  
  7         477  
3 6     6   43 use warnings;
  6         13  
  6         781  
4 6     6   34 use utf8;
  6         21  
  6         316  
5 6     6   166 use 5.010_001;
  6         19  
  6         483  
6              
7 6     6   37 use B;
  6         13  
  6         601  
8 6     6   40 use Carp ();
  6         12  
  6         4878  
9              
10 6     6 0 16167 sub new { bless {}, shift }
11              
12             sub compile {
13 24     24 0 1782 my ($self, $msgid, $fmt, $functions) = @_;
14 24         72 my $code = $self->_compile($msgid, $fmt, $functions);
15 23         77 return $code;
16             }
17              
18             sub _compile {
19 24     24   116 my ($self, $msgid, $str, $functions) = @_;
20              
21 24 100       114 return \$str unless $str =~ /%/;
22              
23 12         20 my @code;
24             my @bind;
25 12         117 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 31 100       119 if ($1) { # Raw string
41 13         27 my $text = $1;
42 13 100       55 if ($text !~ m/[^\x20-\x7E]/s) { # ASCII very safe chars
43 10         24 $text =~ s/\\/\\\\/g;
44 10         64 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         18 push @code, sprintf(q{$bind[%d],}, 0+@bind);
49 3         8 push @bind, $text;
50             }
51             }
52 31 100       236 if ($2) { # \% %%
    100          
    100          
53 2         6 my $text = $2;
54 2         9 $text =~ s/\\/\\\\\\\\/g;
55 2         19 push @code, "'" . $text . "',";
56             }
57             elsif ($3) {
58 4         8 my $function_name = $3;
59 4 100       17 if ($function_name eq '*') {
    100          
60 1         1 $function_name = 'quant';
61             }
62             elsif ($function_name eq '#') {
63 1         4 $function_name = 'numf';
64             }
65              
66 4 100       17 unless (exists $functions->{$function_name}) {
67 1         191 Carp::confess("Language resource compilation error. Unknown function: '${function_name}'");
68             }
69              
70 3         8 my $code = q!$functions->{'! . $function_name . q!'}->(!;
71 3         18 for my $arg (split(/,/, $4)) {
72 5 100       18 if (my $num = $arg =~ /%(.+)/) {
73 3         12 $code .= '$_[' . $num . '], ';
74             }
75             else {
76 2         6 $code .= "'" . $arg . "', ";
77             }
78             }
79 3         6 $code .= '), ';
80 3         18 push @code, $code;
81             }
82             elsif ($5) {
83 9         24 my $arg = $5;
84              
85 9         21 my $var = '';
86 9 100       29 if ($arg eq '*') {
87 2         7 $var = '@_[1 .. $#_],';
88             }
89             else {
90 7         23 $var = '$_[' . $arg . '],';
91             }
92 9         70 push @code, $var;
93             }
94             }
95              
96 11 100       36 if (@code > 1) { # most cases, presumably!
97 9         36 unshift @code, "join '',\n";
98             }
99 11         35 unshift @code, qq!#line 1 "${msgid}"\n!;
100 11         24 unshift @code, "use strict; sub {\n";
101 11         23 push @code, "}\n";
102              
103 4     4   34 my $sub = eval(join '', @code); ## no critic.
  4         9  
  4         958  
  11         1130  
104 11 50       157 die "Language resource compilation error: $@ while evalling" . join('', @code) if $@; # Should be impossible.
105 11         47 return $sub;
106             }
107              
108             1;
109             __END__