File Coverage

blib/lib/Locale/TextDomain/OO/Lexicon/Role/File.pm
Criterion Covered Total %
statement 128 131 97.7
branch 34 40 85.0
condition n/a
subroutine 17 17 100.0
pod 1 1 100.0
total 180 189 95.2


line stmt bran cond sub pod time code
1             package Locale::TextDomain::OO::Lexicon::Role::File; ## no critic (TidyCode)
2            
3 22     22   22208 use strict;
  22         59  
  22         672  
4 22     22   113 use warnings;
  22         50  
  22         669  
5 22     22   132 use Carp qw(confess);
  22         45  
  22         1251  
6 22     22   1215 use Encode qw(decode FB_CROAK);
  22         19396  
  22         1028  
7 22     22   584 use English qw(-no_match_vars $OS_ERROR);
  22         3540  
  22         165  
8 22     22   3175 use Locale::TextDomain::OO::Singleton::Lexicon;
  22         59  
  22         623  
9 22     22   9809 use Locale::TextDomain::OO::Util::ExtractHeader;
  22         29355  
  22         699  
10 22     22   147 use Locale::TextDomain::OO::Util::JoinSplitLexiconKeys;
  22         47  
  22         540  
11 22     22   114 use Moo::Role;
  22         44  
  22         176  
12 22     22   8666 use MooX::Types::MooseLike::Base qw(CodeRef);
  22         46  
  22         1003  
13 22     22   17189 use Path::Tiny qw(path);
  22         245947  
  22         1661  
14 22     22   230 use namespace::autoclean;
  22         50  
  22         208  
15            
16             our $VERSION = '1.034';
17            
18             with qw(
19             Locale::TextDomain::OO::Lexicon::Role::GettextToMaketext
20             Locale::TextDomain::OO::Role::Logger
21             );
22            
23             requires qw(
24             read_messages
25             );
26            
27             has decode_code => (
28             is => 'ro',
29             isa => CodeRef,
30             lazy => 1,
31             default => sub {
32             sub {
33             my ($charset, $text) = @_;
34             defined $text
35             or return $text;
36            
37             return decode( $charset, $text, FB_CROAK );
38             };
39             },
40             );
41            
42             sub _decode_messages {
43 39     39   126 my ($self, $messages_ref) = @_;
44            
45 39         146 my $charset = lc $messages_ref->[0]->{charset};
46 39         72 for my $value ( @{$messages_ref} ) {
  39         105  
47 296         3598 for my $key ( qw( msgid msgid_plural msgstr ) ) {
48 888 100       18406 if ( exists $value->{$key} ) {
49 553         966 for my $text ( $value->{$key} ) {
50 553         9221 $text = $self->decode_code->($charset, $text);
51             }
52             }
53             }
54 296 100       6095 if ( exists $value->{msgstr_plural} ) {
55 92         139 my $got = @{ $value->{msgstr_plural} };
  92         187  
56 92         217 my $expected = $messages_ref->[0]->{nplurals};
57             $got <= $expected or confess sprintf
58             'Count of msgstr_plural=%s but nplurals=%s for msgid="%s" msgid_plural="%s"',
59             $got,
60             $expected,
61             ( exists $value->{msgid} ? $value->{msgid} : q{} ),
62 92 50       244 ( exists $value->{msgid_plural} ? $value->{msgid_plural} : q{} );
    50          
    100          
63 91         145 for my $text ( @{ $value->{msgstr_plural} } ) {
  91         216  
64 219         8643 $text = $self->decode_code->($charset, $text);
65             }
66             }
67             }
68            
69 38         227 return;
70             }
71            
72             sub _my_glob {
73 25     25   91 my ($self, $file) = @_;
74            
75 25         133 my $dirname = $file->parent;
76 25         2713 my $filename = $file->basename;
77            
78             # only one * allowed at all
79 25         365 my $dir_star_count = () = $dirname =~ m{ [*] }xmsg;
80 25         203 my $file_star_count = () = $filename =~ m{ [*] }xmsg;
81 25         63 my $count = $dir_star_count + $file_star_count;
82 25 100       169 $count
83             or return $file;
84 24 50       108 $count > 1
85             and confess 'Only one * in dirname/filename is allowd to reference the language';
86            
87             # one * in filename
88 24 100       79 if ( $file_star_count ) {
89 2         12 ( my $file_regex = quotemeta $filename ) =~ s{\\[*]}{.*?}xms;
90             return +(
91 2         62 sort $dirname->children( qr{\A $file_regex \z}xms )
92             );
93             }
94            
95             # one * in dir
96             # split that dir into left, inner with * and right
97 22         295 my ( $left_dir, $inner_dir, $right_dir )
98             = split qr{( [^/*]* [*] [^/]* )}xms, $dirname;
99 22         376 ( my $inner_dir_regex = quotemeta $inner_dir ) =~ s{\\[*]}{.*?}xms;
100             my @left_and_inner_dirs
101 22         106 = path($left_dir)->children( qr{$inner_dir_regex}xms );
102            
103             return +(
104             sort
105             grep {
106 106         2586 $_->is_file;
107             }
108             map {
109 22         8071 path("$_$right_dir")->child($filename);
  106         4939  
110             }
111             @left_and_inner_dirs
112             );
113             }
114            
115             sub _run_extra_commands {
116 28     28   101 my ($self, $identifier, $instance, $next_data_code) = @_;
117            
118 28 100       116 if ( $identifier eq 'merge_lexicon' ) {
119 1         4 my ( $from1, $from2, $to ) = (
120             $next_data_code->(),
121             $next_data_code->(),
122             $next_data_code->(),
123             );
124 1         6 $instance->merge_lexicon( $from1, $from2, $to );
125 1         8 return 1;
126             }
127 27 50       109 if ( $identifier eq 'copy_lexicon' ) {
128 0         0 my ( $from, $to ) = ( $next_data_code->(), $next_data_code->() );
129 0         0 $instance->copy_lexicon( $from, $to );
130 0         0 return 1;
131             }
132 27 100       104 if ( $identifier eq 'move_lexicon' ) {
133 1         3 my ( $from, $to ) = ( $next_data_code->(), $next_data_code->() );
134 1         6 $instance->move_lexicon( $from, $to );
135 1         8 return 1;
136             }
137 26 100       118 if ( $identifier eq 'delete_lexicon' ) {
138 1         3 my $name = $next_data_code->();
139 1         5 $instance->delete_lexicon($name);
140 1         7 return 1;
141             }
142            
143 25         91 return;
144             }
145            
146             sub lexicon_ref {
147 21     21 1 50225 my ($self, $file_lexicon_ref) = @_;
148            
149 21         239 my $instance = Locale::TextDomain::OO::Singleton::Lexicon->instance;
150 21 100       525 $self->logger and $instance->logger( $self->logger );
151             my $search_dirs = $file_lexicon_ref->{search_dirs}
152 21 50       947 or confess 'Hash key "search_dirs" expected';
153 21         268 my $header_util = Locale::TextDomain::OO::Util::ExtractHeader->instance;
154 21         253 my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys->instance;
155 21         105 my $data = $file_lexicon_ref->{data};
156 21         46 my $index = 0;
157             DATA:
158 21         49 while ( $index < @{ $file_lexicon_ref->{data} } ) {
  48         11018  
159 28         84 my $identifier = $data->[ $index++ ];
160             $self->_run_extra_commands(
161             $identifier,
162             $instance,
163 6     6   20 sub { return $data->[ $index++ ] },
164 28 100       224 ) and next DATA;
165 25         153 my ( $lexicon_key, $lexicon_value )
166             = ( $identifier, $data->[ $index++ ] );
167 25         57 for my $dir ( @{ $search_dirs } ) {
  25         95  
168 25         135 my $file = path( $dir, $lexicon_value );
169 25         1418 my @files = $self->_my_glob($file);
170 25         1085 for ( @files ) {
171 40         7408 my $filename = $_->canonpath;
172 40         267 my $lexicon_language_key = $lexicon_key;
173 40         117 my $language = $filename;
174 40         170 my @parts = split m{[*]}xms, $file;
175 40 100       341 if ( @parts == 2 ) {
176 39         151 substr $language, 0, length $parts[0], q{};
177 39         193 substr $language, - length $parts[1], length $parts[1], q{};
178 39         271 $lexicon_language_key =~ s{[*]}{$language}xms;
179             }
180 40         236 my $messages_ref = $self->read_messages($filename);
181             my $header_msgstr = $messages_ref->[0]->{msgstr}
182 40 50       93966 or confess 'msgstr of header not found';
183 40         122 my $header_ref = $messages_ref->[0];
184 40         9267 %{$header_ref} = (
185             msgid => $header_ref->{msgid},
186 40         110 %{ $header_util->extract_header_msgstr( $header_ref->{msgstr} ) },
  40         366  
187             );
188             $file_lexicon_ref->{gettext_to_maketext}
189 40 100       337 and $self->gettext_to_maketext($messages_ref);
190             $file_lexicon_ref->{decode}
191 40 100       259 and $self->_decode_messages($messages_ref);
192             $instance->data->{$lexicon_language_key} = {
193             map { ## no critic (ComplexMappings)
194 303         458 my $message_ref = $_;
195             my $msg_key = $key_util->join_message_key({(
196             map {
197 303         478 $_ => delete $message_ref->{$_};
  909         2928  
198             }
199             qw( msgctxt msgid msgid_plural )
200             )});
201 303         10472 ( $msg_key => $message_ref );
202 39         80 } @{$messages_ref}
  39         108  
203             };
204 39 100       942 $self->logger and $self->logger->(
205             qq{Lexicon "$lexicon_language_key" loaded from file "$filename".},
206             {
207             object => $self,
208             type => 'debug',
209             event => 'lexicon,load',
210             },
211             );
212             }
213             }
214             }
215            
216 20         118 return $self;
217             }
218            
219             1;
220            
221             __END__