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   66554 use strict;
  7         22  
  7         491  
3 6     6   31 use warnings;
  6         13  
  6         326  
4 6     6   29 use utf8;
  6         12  
  6         231  
5 6     6   156 use 5.010_001;
  6         18  
6              
7 6     6   214 use B;
  6         24  
  6         212  
8 6     6   173 use Carp ();
  6         16  
  6         3589  
9              
10 7     6 0 13607 sub new { bless {}, shift }
11              
12             sub compile {
13 24     24 0 1882 my ($self, $msgid, $fmt, $functions) = @_;
14 24         57 my $code = $self->_compile($msgid, $fmt, $functions);
15 23         59 return $code;
16             }
17              
18             sub _compile {
19 24     24   49 my ($self, $msgid, $str, $functions) = @_;
20              
21 24 100       115 return \$str unless $str =~ /%/;
22              
23 12         24 my @code;
24             my @bind;
25 12         88 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       80 if ($1) { # Raw string
41 13         26 my $text = $1;
42 13 100       44 if ($text !~ m/[^\x20-\x7E]/s) { # ASCII very safe chars
43 10         19 $text =~ s/\\/\\\\/g;
44 10         41 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         19 push @code, sprintf(q{$bind[%d],}, 0+@bind);
49 3         10 push @bind, $text;
50             }
51             }
52 31 100       148 if ($2) { # \% %%
    100          
    100          
53 2         4 my $text = $2;
54 2         6 $text =~ s/\\/\\\\\\\\/g;
55 2         12 push @code, "'" . $text . "',";
56             }
57             elsif ($3) {
58 4         9 my $function_name = $3;
59 4 100       11 if ($function_name eq '*') {
    100          
60 1         2 $function_name = 'quant';
61             }
62             elsif ($function_name eq '#') {
63 1         3 $function_name = 'numf';
64             }
65              
66 4 100       10 unless (exists $functions->{$function_name}) {
67 1         171 Carp::confess("Language resource compilation error. Unknown function: '${function_name}'");
68             }
69              
70 3         7 my $code = q!$functions->{'! . $function_name . q!'}->(!;
71 3         11 for my $arg (split(/,/, $4)) {
72 5 100       17 if (my $num = $arg =~ /%(.+)/) {
73 3         11 $code .= '$_[' . $num . '], ';
74             }
75             else {
76 2         5 $code .= "'" . $arg . "', ";
77             }
78             }
79 3         5 $code .= '), ';
80 3         15 push @code, $code;
81             }
82             elsif ($5) {
83 9         17 my $arg = $5;
84              
85 9         21 my $var = '';
86 9 100       22 if ($arg eq '*') {
87 2         5 $var = '@_[1 .. $#_],';
88             }
89             else {
90 7         22 $var = '$_[' . $arg . '],';
91             }
92 9         40 push @code, $var;
93             }
94             }
95              
96 11 100       30 if (@code > 1) { # most cases, presumably!
97 9         22 unshift @code, "join '',\n";
98             }
99 11         29 unshift @code, qq!#line 1 "${msgid}"\n!;
100 11         25 unshift @code, "use strict; sub {\n";
101 11         21 push @code, "}\n";
102              
103 4     4   183 my $sub = eval(join '', @code); ## no critic.
  4         12  
  4         615  
  11         749  
104 11 50       184 die "Language resource compilation error: $@ while evalling" . join('', @code) if $@; # Should be impossible.
105 11         41 return $sub;
106             }
107              
108             1;
109             __END__