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   18771 use strict;
  22         53  
  22         584  
4 22     22   103 use warnings;
  22         43  
  22         576  
5 22     22   108 use Carp qw(confess);
  22         39  
  22         1056  
6 22     22   1086 use Encode qw(decode FB_CROAK);
  22         17250  
  22         901  
7 22     22   549 use English qw(-no_match_vars $OS_ERROR);
  22         3377  
  22         140  
8 22     22   2820 use Locale::TextDomain::OO::Singleton::Lexicon;
  22         43  
  22         563  
9 22     22   8690 use Locale::TextDomain::OO::Util::ExtractHeader;
  22         25928  
  22         604  
10 22     22   136 use Locale::TextDomain::OO::Util::JoinSplitLexiconKeys;
  22         41  
  22         480  
11 22     22   98 use Moo::Role;
  22         36  
  22         134  
12 22     22   15619 use MooX::Types::MooseLike::Base qw(CodeRef);
  22         43  
  22         1223  
13 22     22   15254 use Path::Tiny qw(path);
  22         221559  
  22         1264  
14 22     22   185 use namespace::autoclean;
  22         48  
  22         160  
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   97 my ($self, $messages_ref) = @_;
44            
45 39         121 my $charset = lc $messages_ref->[0]->{charset};
46 39         71 for my $value ( @{$messages_ref} ) {
  39         87  
47 296         3155 for my $key ( qw( msgid msgid_plural msgstr ) ) {
48 888 100       17053 if ( exists $value->{$key} ) {
49 553         886 for my $text ( $value->{$key} ) {
50 553         8731 $text = $self->decode_code->($charset, $text);
51             }
52             }
53             }
54 296 100       5810 if ( exists $value->{msgstr_plural} ) {
55 92         128 my $got = @{ $value->{msgstr_plural} };
  92         162  
56 92         167 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       237 ( exists $value->{msgid_plural} ? $value->{msgid_plural} : q{} );
    50          
    100          
63 91         134 for my $text ( @{ $value->{msgstr_plural} } ) {
  91         194  
64 219         7532 $text = $self->decode_code->($charset, $text);
65             }
66             }
67             }
68            
69 38         195 return;
70             }
71            
72             sub _my_glob {
73 25     25   67 my ($self, $file) = @_;
74            
75 25         106 my $dirname = $file->parent;
76 25         2180 my $filename = $file->basename;
77            
78             # only one * allowed at all
79 25         300 my $dir_star_count = () = $dirname =~ m{ [*] }xmsg;
80 25         174 my $file_star_count = () = $filename =~ m{ [*] }xmsg;
81 25         51 my $count = $dir_star_count + $file_star_count;
82 25 100       132 $count
83             or return $file;
84 24 50       86 $count > 1
85             and confess 'Only one * in dirname/filename is allowd to reference the language';
86            
87             # one * in filename
88 24 100       67 if ( $file_star_count ) {
89 2         9 ( my $file_regex = quotemeta $filename ) =~ s{\\[*]}{.*?}xms;
90             return +(
91 2         48 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         186 my ( $left_dir, $inner_dir, $right_dir )
98             = split qr{( [^/*]* [*] [^/]* )}xms, $dirname;
99 22         332 ( my $inner_dir_regex = quotemeta $inner_dir ) =~ s{\\[*]}{.*?}xms;
100             my @left_and_inner_dirs
101 22         76 = path($left_dir)->children( qr{$inner_dir_regex}xms );
102            
103             return +(
104             sort
105             grep {
106 106         2308 $_->is_file;
107             }
108             map {
109 22         7338 path("$_$right_dir")->child($filename);
  106         4592  
110             }
111             @left_and_inner_dirs
112             );
113             }
114            
115             sub _run_extra_commands {
116 28     28   90 my ($self, $identifier, $instance, $next_data_code) = @_;
117            
118 28 100       95 if ( $identifier eq 'merge_lexicon' ) {
119 1         3 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         7 return 1;
126             }
127 27 50       79 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       73 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         7 return 1;
136             }
137 26 100       92 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         76 return;
144             }
145            
146             sub lexicon_ref {
147 21     21 1 51170 my ($self, $file_lexicon_ref) = @_;
148            
149 21         185 my $instance = Locale::TextDomain::OO::Singleton::Lexicon->instance;
150 21 100       424 $self->logger and $instance->logger( $self->logger );
151             my $search_dirs = $file_lexicon_ref->{search_dirs}
152 21 50       795 or confess 'Hash key "search_dirs" expected';
153 21         175 my $header_util = Locale::TextDomain::OO::Util::ExtractHeader->instance;
154 21         195 my $key_util = Locale::TextDomain::OO::Util::JoinSplitLexiconKeys->instance;
155 21         89 my $data = $file_lexicon_ref->{data};
156 21         43 my $index = 0;
157             DATA:
158 21         44 while ( $index < @{ $file_lexicon_ref->{data} } ) {
  48         10464  
159 28         74 my $identifier = $data->[ $index++ ];
160             $self->_run_extra_commands(
161             $identifier,
162             $instance,
163 6     6   16 sub { return $data->[ $index++ ] },
164 28 100       177 ) and next DATA;
165 25         123 my ( $lexicon_key, $lexicon_value )
166             = ( $identifier, $data->[ $index++ ] );
167 25         50 for my $dir ( @{ $search_dirs } ) {
  25         62  
168 25         110 my $file = path( $dir, $lexicon_value );
169 25         1129 my @files = $self->_my_glob($file);
170 25         992 for ( @files ) {
171 40         7528 my $filename = $_->canonpath;
172 40         208 my $lexicon_language_key = $lexicon_key;
173 40         84 my $language = $filename;
174 40         135 my @parts = split m{[*]}xms, $file;
175 40 100       299 if ( @parts == 2 ) {
176 39         135 substr $language, 0, length $parts[0], q{};
177 39         180 substr $language, - length $parts[1], length $parts[1], q{};
178 39         241 $lexicon_language_key =~ s{[*]}{$language}xms;
179             }
180 40         185 my $messages_ref = $self->read_messages($filename);
181             my $header_msgstr = $messages_ref->[0]->{msgstr}
182 40 50       83010 or confess 'msgstr of header not found';
183 40         101 my $header_ref = $messages_ref->[0];
184 40         8082 %{$header_ref} = (
185             msgid => $header_ref->{msgid},
186 40         84 %{ $header_util->extract_header_msgstr( $header_ref->{msgstr} ) },
  40         278  
187             );
188             $file_lexicon_ref->{gettext_to_maketext}
189 40 100       256 and $self->gettext_to_maketext($messages_ref);
190             $file_lexicon_ref->{decode}
191 40 100       216 and $self->_decode_messages($messages_ref);
192             $instance->data->{$lexicon_language_key} = {
193             map { ## no critic (ComplexMappings)
194 303         433 my $message_ref = $_;
195             my $msg_key = $key_util->join_message_key({(
196             map {
197 303         435 $_ => delete $message_ref->{$_};
  909         2697  
198             }
199             qw( msgctxt msgid msgid_plural )
200             )});
201 303         9404 ( $msg_key => $message_ref );
202 39         69 } @{$messages_ref}
  39         105  
203             };
204 39 100       806 $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         72 return $self;
217             }
218            
219             1;
220            
221             __END__