File Coverage

blib/lib/Mojolicious/Plugin/Localize/Command/localize.pm
Criterion Covered Total %
statement 88 95 92.6
branch 25 32 78.1
condition 21 31 67.7
subroutine 9 10 90.0
pod 1 1 100.0
total 144 169 85.2


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Localize::Command::localize;
2 1     1   937268 use Mojo::Base 'Mojolicious::Command';
  1         1  
  1         9  
3 1     1   307 use Mojo::Util qw/quote encode/;
  1         2  
  1         107  
4 1     1   6 use Mojo::Date;
  1         1  
  1         8  
5 1     1   41 use Getopt::Long qw(GetOptionsFromArray :config no_auto_abbrev no_ignore_case);
  1         1  
  1         8  
6              
7             # TODO:
8             # Probably do:
9             # http://irclog.perlgeek.de/mojo/2016-09-22#i_13257554
10              
11             has description => 'Generate dictionary files for Localize';
12             has usage => sub { shift->extract_usage };
13              
14             our $SPECIAL = '!SPECIAL!'; # Special locale
15              
16 1   50 1   284 use constant DEBUG => $ENV{MOJO_LOCALIZE_DEBUG} || 0;
  1         3  
  1         1695  
17              
18             has [qw/base lang controller/];
19              
20              
21             # Generate dictionary template
22             sub run {
23 9     9 1 124645 my ($self, $lang, @args) = @_;
24              
25 9         40 $self->lang($lang);
26              
27 9         71 my $app = $self->app;
28              
29 9         78 GetOptionsFromArray \@args,
30             'b|base=s' => \(my $base = 'en'),
31             'o|output=s' => \(my $output = '');
32              
33             # Unknown command
34 9 100 50     5059 print $self->usage and return unless $self->lang;
35              
36             # Set base language
37 8         62 $self->base($base);
38              
39             # Initialize key store
40 8         46 $self->{keys} = {};
41              
42             # Get generated dictionary
43 8         43 my $dict = $app->localize->dictionary;
44              
45             # Set controller
46 8         121 $self->controller($app->build_controller);
47              
48             # Setting an unlikely locale
49 8         483 $self->controller->stash('localize.locale' => [$SPECIAL]);
50              
51             # Recursive investigate the dictionary
52 8         150 $self->_investigate($dict, [], 0);
53              
54 8         19 my $data = '# Dictionary template generated ';
55 8         76 $data .= Mojo::Date->new(time);
56 8         397 $data .= "\n\n{\n" . $self->_filter->_print . "};\n";
57              
58 8   66     29 $output ||= $app->moniker . '.' . $self->lang . '.dict';
59              
60             # Generate file
61 8 100       485 if (-e $output) {
    50          
62 1         4 warn quote($output) . " already exists and is not overwritten.\n\n"
63             }
64             elsif ($self->write_rel_file($output, encode('UTF-8', $data))) {
65 7         3815 say quote($output) . " written.\n";
66             };
67 8         472 print "\n";
68             };
69              
70              
71             # Investigate dictionary entry and check for usage
72             sub _investigate {
73 154     154   302 my ($self, $dict, $path, $level) = @_;
74              
75 154 100 66     532 if (!ref $dict || ref $dict eq 'SCALAR' || ref $dict eq 'CODE') {
    50 66        
76              
77             # Check elements of the path
78 90         159 my @elements = @{$path}[0..$level - 1];
  90         213  
79              
80             # Key is not localed
81 90 100       337 return unless grep /[\*\+]/, @elements;
82              
83             # Join the missing key
84 38         79 my $key = join('_', @elements);
85              
86 38         91 $self->{keys}->{$key} = $dict;
87              
88 38         117 return;
89             }
90              
91             elsif (ref $dict eq 'ARRAY') {
92 0         0 warn 'Arrays are not valid dictionary values';
93 0         0 return;
94             };
95              
96             # Set local $_ to nested helber for preferred subroutines
97 64         116 local $_ = $self->controller->localize;
98              
99             # Define the example branch
100 64         724 my $locale_example;
101              
102             # There is a locale branch
103             my $loc_act;
104 64 100 66     189 if (($loc_act = $dict->{_}) &&
      66        
      66        
      100        
105             (ref($loc_act) eq 'CODE') &&
106             ($loc_act = $dict->{_}->($self->controller)) &&
107             (ref($loc_act) eq 'ARRAY') &&
108             ($loc_act->[0] eq $SPECIAL)) {
109              
110             # The output already exists
111 22 100       229 if (exists $dict->{$self->lang}) {
112 8         44 $path->[$level] = '+';
113 8         16 $locale_example = $self->lang;
114              
115 8         26 if (DEBUG) {
116             warn '[DICT] Locale branch at path ' .
117             quote(_key($path, $level + 1)) . " and level [$level]";
118             };
119              
120             # Follow the locale
121             $self->_investigate(
122 8         24 $dict->{$locale_example},
123             $path,
124             $level + 1
125             );
126             };
127              
128             # Define the output for the path
129 22         78 $path->[$level] = '*';
130              
131             # The input example branch exists
132 22 100 33     41 if ($dict->{$self->base}) {
    50          
133 21         86 $locale_example = $self->base;
134             }
135              
136             # A default branch exists
137             elsif ($dict->{'-'} && $dict->{$dict->{'-'}}) {
138 0         0 $locale_example = $dict->{'-'};
139             };
140              
141             # Example path is missing - can't follow!
142 22 100       82 unless ($locale_example) {
143 1         2 warn '[DICT] No example path defined for locale branch ' .
144             quote(_key($path, $level + 1)) if DEBUG;
145 1         3 return;
146             };
147              
148 21         28 if (DEBUG) {
149             warn '[DICT] Locale branch at path ' .
150             quote(_key($path, $level + 1)) . ' and level [' . $level . ']';
151             };
152              
153             # Follow the locale
154             $self->_investigate(
155 21         47 $dict->{$locale_example},
156             $path,
157             $level + 1
158             );
159             };
160              
161              
162             # FOLLOW ALL KEYS!
163 63 100       161 foreach (grep { $_ ne '-' && $_ ne '_' } keys %$dict) {
  150         424  
164              
165             # The key is a default key
166 117 100 100     238 if ($dict->{'-'} && $_ eq $dict->{'-'}) {
167              
168             # Prefix key value with default prefix
169 10         23 $path->[$level] = '-' . $_;
170             }
171              
172             # Set key value in path
173             else {
174 107         189 $path->[$level] = $_;
175             };
176              
177 117         205 $self->_investigate($dict->{$_}, $path, $level + 1);
178             };
179             };
180              
181              
182             # Return the current key
183             sub _key {
184 0     0   0 return join('_', @{$_[0]}[0..$_[1] - 1])
  0         0  
185             };
186              
187              
188             # Filter all locale keys already defined
189             sub _filter {
190 8     8   12 my $self = shift;
191              
192             # Iterate over all locale given keys
193 8         16 foreach (grep { index($_, '+') >= 0 } keys %{$self->{keys}}) {
  38         72  
  8         25  
194              
195             # Delete all given keys
196 11         17 delete $self->{keys}->{$_};
197              
198             # Delete all keys locale keys that are not already given
199 11         24 $_ =~ tr/\+/\*/;
200 11         20 delete $self->{keys}->{$_};
201             };
202              
203 8         22 return $self;
204             };
205              
206              
207             # Print out all keys
208             sub _print {
209 8     8   16 my $self = shift;
210              
211 8         16 my $out = $self->lang;
212              
213 8         34 my %new_keys;
214 8         14 while (my ($key, $value) = each %{$self->{keys}}) {
  27         75  
215 19         54 $key =~ s/\*/$out/g;
216 19         48 $new_keys{$key} = $value;
217             };
218              
219 8         16 my $template = '';
220              
221             # Iterate over all stored keys
222 8         42 foreach my $key (sort { lc($a) cmp lc($b) } (keys %new_keys)) {
  12         37  
223              
224 18         64 $template .= ' # ' . quote($key) . ' => ';
225              
226 18         98 my $value = $new_keys{$key};
227              
228             # Print example entry
229 18 50       42 if (!ref $value) {
    50          
    0          
230 0         0 $template .= quote($value) . ",";
231             }
232              
233             # Print scalar value
234             elsif (ref $value eq 'SCALAR') {
235 18         29 $template .= quote($$value) . ",";
236             }
237              
238             # Print sub
239             elsif (ref $value eq 'CODE') {
240 0         0 $template .= "sub { ... },";
241             };
242              
243             # Add newline
244 18         91 $template .= "\n"
245             };
246              
247 8         23 return $template;
248             };
249              
250              
251             1;
252              
253             __END__