File Coverage

blib/lib/Locale/Utils/PlaceholderBabelFish.pm
Criterion Covered Total %
statement 73 73 100.0
branch 28 34 82.3
condition 1 3 33.3
subroutine 15 15 100.0
pod 2 2 100.0
total 119 127 93.7


line stmt bran cond sub pod time code
1             package Locale::Utils::PlaceholderBabelFish; ## no critic (TidyCode)
2            
3 5     5   170741 use strict;
  5         18  
  5         193  
4 5     5   42 use warnings;
  5         16  
  5         201  
5 5     5   38 use Carp qw(confess);
  5         20  
  5         321  
6 5     5   2755 use HTML::Entities qw(encode_entities);
  5         33792  
  5         511  
7 5     5   51 use List::Util qw(min);
  5         13  
  5         380  
8 5     5   2878 use Moo;
  5         62646  
  5         34  
9 5     5   9273 use MooX::StrictConstructor;
  5         63473  
  5         31  
10 5     5   110307 use MooX::Types::MooseLike::Base qw(Bool CodeRef);
  5         29348  
  5         515  
11 5     5   65 use Scalar::Util qw(looks_like_number);
  5         15  
  5         281  
12 5     5   2875 use namespace::autoclean;
  5         64206  
  5         26  
13            
14             our $VERSION = '0.005';
15            
16             has is_strict => (
17             is => 'rw',
18             isa => Bool,
19             );
20            
21             sub default_modifier_code {
22             return sub {
23 3     3   33 my ( $value, $attributes ) = @_;
24            
25 3 100       23 if ( $attributes =~ m{ \b html \b }xms ) {
26 1         10 $value = encode_entities( $value, q{<>&"} );
27             }
28            
29 3         388 return $value;
30             }
31 2     2 1 86 };
32            
33             has modifier_code => (
34             is => 'rw',
35             isa => CodeRef,
36             clearer => 'clear_modifier_code',
37             lazy => 1,
38             default => \&default_modifier_code,
39             );
40            
41             has plural_code => (
42             is => 'rw',
43             isa => CodeRef,
44             lazy => 1,
45             default => sub {
46             return sub {
47             my $n = shift;
48             0 + (
49             $n != 1 # en
50             );
51             };
52             },
53             clearer => 'clear_plural_code',
54             );
55            
56             sub _mangle_value {
57 47     47   196 my ($self, $placeholder, $value, $attribute) = @_;
58            
59 47 100       268 defined $value
    100          
60             or return $self->is_strict ? $placeholder : q{};
61 41 100       291 defined $attribute
62             or return $value;
63 7 50       192 $self->modifier_code
64             or return $value;
65 7         311 $value = $self->modifier_code->($value, $attribute);
66 7 50       111 defined $value
67             or confess 'modifier_code returns nothing or undef';
68            
69 7         44 return $value;
70             }
71            
72             sub expand_babel_fish {
73 26     26 1 8201 my ($self, $text, @args) = @_;
74            
75 26 100       117 defined $text
76             or return $text;
77 25 100       168 my $arg_ref = @args == 1
    50          
    100          
78             ? ( ref $args[0] eq 'HASH' ? $args[0] : { count => $args[0] } )
79             : {
80             @args % 2
81             ? confess 'Arguments expected pairwise'
82             : @args
83             };
84            
85             # placeholders
86 25         73 my $regex = join q{|}, map { quotemeta } keys %{$arg_ref};
  38         155  
  25         123  
87             ## no critic (EscapedMetacharacters)
88 25         1042 $text =~ s{
89             ( \\ [#] ) # escaped
90             |
91             (
92             [#] \{
93             ( $regex ) # placeholder
94             (?: [ ]* [:] ( [^\}]+ ) )? # attribute
95             \}
96             )
97             }
98             {
99             $1
100             ? $1
101 50 100       342 : $self->_mangle_value($2, $arg_ref->{$3}, $4)
102             }xmsge;
103             ## use critic (EscapedMetacharacters)
104            
105             # plural
106             my $replace_code = sub {
107 21     21   80 my ( $match, $inner, $count ) = @_;
108            
109 21 100       109 looks_like_number($count)
110             or return $match;
111 16         47 $inner =~ s{ \\ [|] }{\0}xmsg;
112 16         31 my @special_plurals;
113             my @plurals
114             = map {
115             m{ \A [=] ( \d+ ) \s+ ( .* ) \z }xms
116 35 100       121 ? do {
117 1         6 push @special_plurals, [$1, $2];
118 1         4 ();
119             }
120             : $_;
121             }
122             map { ## no critic (ComplexMappings)
123 16         106 my $item = $_;
  35         71  
124 35         74 $item =~ s{ \0 }{\\|}xmsg;
125 35         87 $item;
126             }
127             split qr{ [|] }xms, $inner;
128 16         61 for my $plural ( @special_plurals ) {
129 1 50 33     12 if ( defined $plural->[0] && $plural->[0] == $count ) {
130 1         7 return $plural->[1];
131             }
132             }
133             @plurals
134 15 50       47 or return $match;
135 15         340 my $index = $self->plural_code->($count);
136 15         137 $index = min( $index, $#plurals );
137            
138 15         85 return $plurals[$index];
139 25         250 };
140             ## no critic (EscapedMetacharacters)
141 25         171 $text =~ s{
142             ( \\ \( \( ) # $1: escaped
143             |
144             ( # $2: match
145             \( \( # open
146             ( .*? ) # $3: inner
147             \) \) # close
148             (?: [:] ( \w+ ) )? # $4: count variable name
149             )
150             }
151             {
152             $1
153             ? $1
154             : $replace_code->( $2, $3, $4 ? $arg_ref->{$4} : $arg_ref->{count} )
155 21 100       126 }xmsge;
    50          
156             ## use critic (EscapedMetacharacters)
157            
158             # unescape
159 25         100 $text =~ s{ \\ (.) }{$1}xmsg;
160            
161 25         387 return $text;
162             }
163            
164             __PACKAGE__->meta->make_immutable;
165            
166             1;
167            
168             __END__