| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Mojolicious::Plugin::Localize; |
|
2
|
12
|
|
|
12
|
|
8886652
|
use Mojo::Base 'Mojolicious::Plugin'; |
|
|
12
|
|
|
|
|
31
|
|
|
|
12
|
|
|
|
|
92
|
|
|
3
|
12
|
|
|
12
|
|
3541
|
use Mojo::Util qw/decode/; |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
847
|
|
|
4
|
12
|
|
|
12
|
|
117
|
use Mojo::File qw/path/; |
|
|
12
|
|
|
|
|
21
|
|
|
|
12
|
|
|
|
|
608
|
|
|
5
|
12
|
|
|
12
|
|
5602
|
use Mojolicious::Plugin::Config; |
|
|
12
|
|
|
|
|
13369
|
|
|
|
12
|
|
|
|
|
101
|
|
|
6
|
12
|
|
|
12
|
|
542
|
use File::Spec::Functions 'file_name_is_absolute'; |
|
|
12
|
|
|
|
|
25
|
|
|
|
12
|
|
|
|
|
692
|
|
|
7
|
12
|
|
|
12
|
|
6573
|
use List::MoreUtils 'uniq'; |
|
|
12
|
|
|
|
|
171312
|
|
|
|
12
|
|
|
|
|
72
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# TODO: |
|
10
|
|
|
|
|
|
|
# Wrap http://search.cpan.org/~reneeb/Mojolicious-Plugin-I18NUtils-0.05/lib/Mojolicious/Plugin/I18NUtils.pm |
|
11
|
|
|
|
|
|
|
# TODO: |
|
12
|
|
|
|
|
|
|
# do not backtrack on upper case dictionary keys |
|
13
|
|
|
|
|
|
|
# TODO: |
|
14
|
|
|
|
|
|
|
# Support prefixes in dictionary |
|
15
|
|
|
|
|
|
|
# TODO: |
|
16
|
|
|
|
|
|
|
# Support locale sub in dictionary |
|
17
|
|
|
|
|
|
|
# TODO: |
|
18
|
|
|
|
|
|
|
# 'd' is probably better than 'loc' |
|
19
|
|
|
|
|
|
|
# 'd' for dictionary lookup |
|
20
|
|
|
|
|
|
|
# TODO: |
|
21
|
|
|
|
|
|
|
# use Hash::Merge or Hash::Merge::Small |
|
22
|
|
|
|
|
|
|
# TODO: |
|
23
|
|
|
|
|
|
|
# Use Mojo::Template directly |
|
24
|
|
|
|
|
|
|
# TODO: |
|
25
|
|
|
|
|
|
|
# deal with: |
|
26
|
|
|
|
|
|
|
# <%= numsep $g_count %> <%= quant $g_count, 'guest', 'guests' %> online.' |
|
27
|
|
|
|
|
|
|
# TODO: |
|
28
|
|
|
|
|
|
|
# Deal with bidirectional text |
|
29
|
|
|
|
|
|
|
|
|
30
|
12
|
|
50
|
12
|
|
11798
|
use constant DEBUG => $ENV{MOJO_LOCALIZE_DEBUG} || 0; |
|
|
12
|
|
|
|
|
23
|
|
|
|
12
|
|
|
|
|
42080
|
|
|
31
|
|
|
|
|
|
|
our $VERSION = '0.23'; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
has 'log'; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Warning: This only works for default EP templates |
|
36
|
|
|
|
|
|
|
our $TEMPLATE_INDICATOR = qr/(?:^\s*\%)|<\%/m; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Register plugin |
|
39
|
|
|
|
|
|
|
sub register { |
|
40
|
49
|
|
|
49
|
1
|
330630
|
my ($self, $mojo, $param) = @_; |
|
41
|
|
|
|
|
|
|
|
|
42
|
49
|
|
|
|
|
188
|
my (@dict, @resources); |
|
43
|
49
|
100
|
|
|
|
332
|
@dict = ($param->{dict}) if $param->{dict}; # Hashes |
|
44
|
49
|
100
|
|
|
|
234
|
@resources = @{$param->{resources}} if $param->{resources}; # File names |
|
|
2
|
|
|
|
|
11
|
|
|
45
|
|
|
|
|
|
|
|
|
46
|
49
|
|
|
|
|
279
|
$self->log($mojo->log); |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Not yet initialized |
|
49
|
49
|
100
|
|
|
|
1547
|
unless ($mojo->renderer->helpers->{loc}) { |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# Load parameter from config file |
|
52
|
13
|
100
|
|
|
|
289
|
if (my $c_param = $mojo->config('Localize')) { |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Prefer the configuration dictionary |
|
55
|
1
|
50
|
|
|
|
17
|
push @dict, $c_param->{dict} if $c_param->{dict}; |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# Prefer the configuration override parameter |
|
58
|
1
|
50
|
|
|
|
3
|
$param->{override} = $c_param->{override} if $c_param->{override}; |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Add configuration resources |
|
61
|
1
|
50
|
|
|
|
3
|
if ($c_param->{resources}) { |
|
62
|
1
|
|
|
|
|
2
|
unshift @resources, @{$c_param->{resources}}; |
|
|
1
|
|
|
|
|
2
|
|
|
63
|
|
|
|
|
|
|
}; |
|
64
|
|
|
|
|
|
|
}; |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Load default helper |
|
67
|
13
|
|
|
|
|
262
|
$mojo->plugin('Localize::Quantify'); |
|
68
|
13
|
|
|
|
|
1713
|
$mojo->plugin('Localize::Locale'); |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Add 'generate dictionary' command |
|
71
|
13
|
|
|
|
|
5056
|
push @{$mojo->commands->namespaces}, __PACKAGE__ . '::Command'; |
|
|
13
|
|
|
|
|
133
|
|
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Lookup a dictionary key and return the value |
|
74
|
|
|
|
|
|
|
$mojo->helper( |
|
75
|
|
|
|
|
|
|
loc => sub { |
|
76
|
124
|
|
|
124
|
|
78549
|
my $c = shift; |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# Nothing to look up |
|
79
|
124
|
100
|
100
|
|
|
797
|
return '' unless scalar @_ && $_[0]; |
|
80
|
|
|
|
|
|
|
|
|
81
|
120
|
|
|
|
|
562
|
my $key = [split('_', shift)]; |
|
82
|
|
|
|
|
|
|
|
|
83
|
120
|
|
|
|
|
222
|
if (DEBUG) { |
|
84
|
|
|
|
|
|
|
_debug($c->app, '[LOOKUP] Search for "' . join('_', @$key) . '"'); |
|
85
|
|
|
|
|
|
|
}; |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# If a default entry is given, get it |
|
88
|
120
|
100
|
100
|
|
|
386
|
my $default_entry = shift if @_ && @_ % 2 != 0; |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Store all other values in the stash |
|
91
|
120
|
|
|
|
|
292
|
my %stash = @_; |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Return dictionary entry or default entry |
|
94
|
120
|
|
100
|
|
|
532
|
return _lookup($c, \%stash, $c->stash('localize.dict'), $key, 0) || |
|
|
|
|
100
|
|
|
|
|
|
95
|
|
|
|
|
|
|
$default_entry // ''; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
13
|
|
|
|
|
1134
|
); |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Return the dictionary reference |
|
101
|
|
|
|
|
|
|
$mojo->helper( |
|
102
|
|
|
|
|
|
|
'localize.dictionary' => sub { |
|
103
|
|
|
|
|
|
|
# Return the complete dictionary in case no parameter is defined |
|
104
|
|
|
|
|
|
|
# This is not documented and may change in further versions |
|
105
|
20
|
|
|
20
|
|
11230
|
return $_[0]->stash('localize.dict'); |
|
106
|
|
|
|
|
|
|
} |
|
107
|
13
|
|
|
|
|
962
|
); |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Return the prefered path |
|
110
|
|
|
|
|
|
|
$mojo->helper( |
|
111
|
|
|
|
|
|
|
'localize.preference' => sub { |
|
112
|
4
|
|
|
4
|
|
388
|
my $c = shift; |
|
113
|
|
|
|
|
|
|
|
|
114
|
4
|
|
|
|
|
13
|
my $stash = $c->stash; |
|
115
|
4
|
50
|
|
|
|
28
|
return $stash->{'localize.preference'} if $stash->{'localize.preference'}; |
|
116
|
|
|
|
|
|
|
|
|
117
|
4
|
|
100
|
|
|
15
|
my $key = [split('_', shift // '')]; |
|
118
|
4
|
|
|
|
|
9
|
my $dict = $c->stash('localize.dict'); |
|
119
|
|
|
|
|
|
|
|
|
120
|
4
|
|
|
|
|
23
|
if (DEBUG) { |
|
121
|
|
|
|
|
|
|
_debug($c->app, '[PREF] Look for prefered key for "' . join('_', @$key) . '"'); |
|
122
|
|
|
|
|
|
|
}; |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# If a default entry is given, get it |
|
125
|
4
|
|
|
|
|
6
|
my $default_entry = shift; |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Return dictionary key - so pass the "find_pref" parameter |
|
128
|
4
|
|
33
|
|
|
6
|
$stash->{'localize.preference'} = _lookup($c, {}, $c->stash('localize.dict'), $key, 0, 1) || |
|
|
|
|
50
|
|
|
|
|
|
129
|
|
|
|
|
|
|
$default_entry // ''; |
|
130
|
4
|
|
|
|
|
20
|
return $stash->{'localize.preference'}; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
13
|
|
|
|
|
3483
|
); |
|
133
|
|
|
|
|
|
|
|
|
134
|
13
|
|
|
|
|
3832
|
$mojo->defaults('localize.dict' => {}); |
|
135
|
|
|
|
|
|
|
}; |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Merge dictionary resources |
|
138
|
49
|
100
|
|
|
|
884
|
if (@resources) { |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Create config loader |
|
141
|
3
|
|
|
|
|
24
|
my $config_loader = Mojolicious::Plugin::Config->new; |
|
142
|
3
|
|
|
|
|
30
|
my $home = $mojo->home; |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Load files |
|
145
|
3
|
|
|
|
|
26
|
foreach my $file (uniq @resources) { |
|
146
|
|
|
|
|
|
|
|
|
147
|
4
|
100
|
|
|
|
25
|
$file = $home->rel_file($file) unless file_name_is_absolute $file; |
|
148
|
|
|
|
|
|
|
|
|
149
|
4
|
|
|
|
|
126
|
if (DEBUG) { |
|
150
|
|
|
|
|
|
|
_debug($mojo, "Load dictionary $file"); |
|
151
|
|
|
|
|
|
|
}; |
|
152
|
|
|
|
|
|
|
|
|
153
|
4
|
50
|
|
|
|
16
|
if (-e $file) { |
|
154
|
4
|
50
|
|
|
|
174
|
if (my $dict = $config_loader->load($file, undef, $mojo)) { |
|
155
|
4
|
|
|
|
|
2288
|
unshift @dict, [$dict, $file]; |
|
156
|
4
|
|
|
|
|
22
|
_debug($mojo, qq!Successfully loaded dictionary "$file"!); |
|
157
|
4
|
|
|
|
|
79
|
next; |
|
158
|
|
|
|
|
|
|
}; |
|
159
|
|
|
|
|
|
|
}; |
|
160
|
0
|
|
|
|
|
0
|
$mojo->log->warn(qq!Unable to load dictionary file "$file"!); |
|
161
|
|
|
|
|
|
|
}; |
|
162
|
|
|
|
|
|
|
}; |
|
163
|
|
|
|
|
|
|
|
|
164
|
49
|
|
|
|
|
218
|
my $dict_global = $mojo->defaults('localize.dict'); |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Merge dictionary hashes |
|
167
|
49
|
|
|
|
|
605
|
foreach (@dict) { |
|
168
|
49
|
|
66
|
|
|
278
|
my $is_array = ref $_ && ref $_ eq 'ARRAY'; |
|
169
|
|
|
|
|
|
|
|
|
170
|
49
|
|
|
|
|
105
|
if (DEBUG) { |
|
171
|
|
|
|
|
|
|
_debug( |
|
172
|
|
|
|
|
|
|
$mojo, |
|
173
|
|
|
|
|
|
|
'[MERGE] Start merging' . |
|
174
|
|
|
|
|
|
|
($is_array ? (' of ' . $_->[1]) : '') |
|
175
|
|
|
|
|
|
|
); |
|
176
|
|
|
|
|
|
|
}; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Merge to global dictionary |
|
179
|
49
|
100
|
|
|
|
326
|
$self->_merge($dict_global, $is_array ? $_->[0] : $_, $param->{override}); |
|
180
|
|
|
|
|
|
|
}; |
|
181
|
|
|
|
|
|
|
}; |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# Unflatten short notation |
|
185
|
|
|
|
|
|
|
sub _unflatten { |
|
186
|
12
|
|
|
12
|
|
29
|
my ($key, $dict) = @_; |
|
187
|
12
|
|
|
|
|
27
|
my $k = $$key; |
|
188
|
12
|
|
|
|
|
24
|
my $g_hash = $dict->{$k}; |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Check for preferred key |
|
191
|
12
|
100
|
|
|
|
51
|
if (substr($k, -1, 1) eq '_') { |
|
192
|
1
|
|
|
|
|
5
|
$g_hash = { _ => $g_hash }; |
|
193
|
1
|
|
|
|
|
4
|
chop $k; |
|
194
|
|
|
|
|
|
|
}; |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Build verbose tree |
|
197
|
12
|
|
|
|
|
122
|
$g_hash = { $1 => $g_hash } while $k =~ s/_([^_]+)$//; |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Set root key |
|
200
|
12
|
|
|
|
|
31
|
$$key = $k; |
|
201
|
12
|
|
|
|
|
35
|
$dict->{$k} = $g_hash; |
|
202
|
|
|
|
|
|
|
}; |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Store value as string or code reference |
|
206
|
|
|
|
|
|
|
sub _store { |
|
207
|
126
|
|
|
126
|
|
262
|
my $value = $_[0]; |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# Is template - store as reference |
|
210
|
126
|
100
|
100
|
|
|
1174
|
return $value if ref $value || $value =~ $TEMPLATE_INDICATOR; |
|
211
|
113
|
|
|
|
|
496
|
return \$value; |
|
212
|
|
|
|
|
|
|
}; |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Merge dictionaries |
|
216
|
|
|
|
|
|
|
sub _merge { |
|
217
|
170
|
|
|
170
|
|
419
|
my ($self, $dict_global, $dict, $override) = @_; |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# Iterate over all keys |
|
220
|
170
|
|
|
|
|
480
|
foreach my $k (keys %$dict) { |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# This is a short notation key |
|
223
|
299
|
100
|
|
|
|
791
|
if (index($k, '_') > 0) { |
|
|
|
100
|
|
|
|
|
|
|
224
|
12
|
|
|
|
|
21
|
_debug($self, qq![MERGE] Unflatten "$k"!) if DEBUG; |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Unflatten short notation |
|
227
|
12
|
|
|
|
|
45
|
_unflatten(\$k, $dict); |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Set preferred key |
|
231
|
|
|
|
|
|
|
elsif ($k eq '_') { |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# If override or not set yet, set the new preferred key |
|
234
|
47
|
100
|
100
|
|
|
229
|
if ($override || !defined $dict_global->{_}) { |
|
235
|
|
|
|
|
|
|
|
|
236
|
46
|
|
|
|
|
74
|
_debug($self, qq![MERGE] Override "_"!) if DEBUG; |
|
237
|
46
|
|
|
|
|
126
|
$dict_global->{_} = $dict->{_}; |
|
238
|
|
|
|
|
|
|
}; |
|
239
|
|
|
|
|
|
|
|
|
240
|
47
|
|
|
|
|
201
|
next; |
|
241
|
|
|
|
|
|
|
}; |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# This is a default key |
|
244
|
252
|
100
|
|
|
|
522
|
if (index($k, '-') == 0) { |
|
245
|
35
|
|
|
|
|
60
|
my $standalone = 0; |
|
246
|
|
|
|
|
|
|
|
|
247
|
35
|
|
|
|
|
72
|
_debug($self, qq![MERGE] Try to set default key with "$k"!) if DEBUG; |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# This is a prefixed default key |
|
250
|
35
|
100
|
|
|
|
91
|
if (length($k) > 1) { |
|
251
|
32
|
|
|
|
|
81
|
$k = substr($k, 1); |
|
252
|
32
|
|
|
|
|
122
|
$dict->{$k} = delete $dict->{"-$k"}; |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# This is a standalone default key |
|
256
|
|
|
|
|
|
|
else { |
|
257
|
3
|
|
|
|
|
14
|
$k = $dict->{'-'}; |
|
258
|
3
|
|
|
|
|
6
|
$standalone = 1; |
|
259
|
|
|
|
|
|
|
}; |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# If override or not set yet, set the new default key |
|
262
|
35
|
100
|
100
|
|
|
158
|
if ($override || !defined $dict_global->{'-'}) { |
|
263
|
|
|
|
|
|
|
|
|
264
|
34
|
|
|
|
|
48
|
_debug($self, qq![MERGE] Override default key with "$k"!) if DEBUG; |
|
265
|
34
|
|
|
|
|
96
|
$dict_global->{'-'} = $k; |
|
266
|
|
|
|
|
|
|
}; |
|
267
|
|
|
|
|
|
|
|
|
268
|
35
|
100
|
|
|
|
115
|
next if $standalone; |
|
269
|
|
|
|
|
|
|
}; |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# Insert key - if it not yet exists |
|
272
|
249
|
100
|
100
|
|
|
662
|
if (!$dict_global->{$k}) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Merge the tree |
|
275
|
220
|
100
|
|
|
|
417
|
if (ref $dict->{$k} eq 'HASH') { |
|
276
|
97
|
|
|
|
|
365
|
$self->_merge($dict_global->{$k} = {}, $dict->{$k}, $override); |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
# Store the plain value |
|
280
|
|
|
|
|
|
|
else { |
|
281
|
123
|
|
|
|
|
303
|
$dict_global->{$k} = _store($dict->{$k}); |
|
282
|
|
|
|
|
|
|
}; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# Merge key, when both are hashes |
|
286
|
|
|
|
|
|
|
elsif (ref($dict_global->{$k}) eq ref($dict->{$k}) && ref($dict_global->{$k}) eq 'HASH') { |
|
287
|
24
|
|
|
|
|
81
|
$self->_merge($dict_global->{$k}, $dict->{$k}, $override); |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Override global and store the plain value |
|
291
|
|
|
|
|
|
|
elsif ($override) { |
|
292
|
3
|
|
|
|
|
21
|
$dict_global->{$k} = _store($dict->{$k}); |
|
293
|
|
|
|
|
|
|
}; |
|
294
|
|
|
|
|
|
|
}; |
|
295
|
|
|
|
|
|
|
}; |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub _mark { |
|
298
|
0
|
|
|
0
|
|
0
|
my ($keys, $level) = @_; |
|
299
|
0
|
|
|
|
|
0
|
my @x = (); |
|
300
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i <= $#$keys; $i++) { |
|
301
|
0
|
0
|
|
|
|
0
|
if ($i == $level) { |
|
302
|
0
|
|
|
|
|
0
|
push @x, '[' . $keys->[$i] . ']'; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
else { |
|
305
|
0
|
|
|
|
|
0
|
push @x, $keys->[$i]; |
|
306
|
|
|
|
|
|
|
}; |
|
307
|
|
|
|
|
|
|
}; |
|
308
|
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
0
|
return join('_',@x); |
|
310
|
|
|
|
|
|
|
}; |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# Lookup dictionary entry recursively |
|
313
|
|
|
|
|
|
|
sub _lookup { |
|
314
|
351
|
|
|
351
|
|
2156
|
my ($c, $stash, $dict, $key, $level, $find_pref) = @_; |
|
315
|
|
|
|
|
|
|
# $c is the controller object |
|
316
|
|
|
|
|
|
|
# $stash contains a hash reference of stash values |
|
317
|
|
|
|
|
|
|
# $dict contains the dictionary at the current level |
|
318
|
|
|
|
|
|
|
# $key is the key array passed to the resolver |
|
319
|
|
|
|
|
|
|
# $level is the current position in the key |
|
320
|
|
|
|
|
|
|
# $find_pref is a boolean value indicating that no value is looked up |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Get the current input element to consume |
|
323
|
351
|
|
|
|
|
530
|
my @keys; |
|
324
|
351
|
100
|
|
|
|
880
|
if (my $primary = $key->[$level]) { |
|
325
|
298
|
|
|
|
|
628
|
@keys = ($primary); |
|
326
|
|
|
|
|
|
|
|
|
327
|
298
|
|
|
|
|
382
|
if (DEBUG) { |
|
328
|
|
|
|
|
|
|
_debug($c->app, qq![LOOKUP] There is a primary key "$primary" at input level [$level]!); |
|
329
|
|
|
|
|
|
|
_debug($c->app, qq![LOOKUP] at "! . _mark($key, $level) . '"'); |
|
330
|
|
|
|
|
|
|
}; |
|
331
|
|
|
|
|
|
|
}; |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# No primary key given |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Check all possibilities |
|
336
|
351
|
|
|
|
|
487
|
my $pos = 0; |
|
337
|
351
|
|
|
|
|
566
|
my $lazy = 0; |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# Iterate over all possible key fragments |
|
341
|
351
|
|
|
|
|
484
|
while () { |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# No more keys |
|
344
|
482
|
100
|
|
|
|
914
|
if (!$keys[$pos]) { |
|
345
|
|
|
|
|
|
|
|
|
346
|
150
|
|
|
|
|
192
|
if (DEBUG) { |
|
347
|
|
|
|
|
|
|
_debug( |
|
348
|
|
|
|
|
|
|
$c->app, |
|
349
|
|
|
|
|
|
|
"[LOOKUP] There is no more key at position $pos on input level [$level]" |
|
350
|
|
|
|
|
|
|
); |
|
351
|
|
|
|
|
|
|
}; |
|
352
|
|
|
|
|
|
|
|
|
353
|
150
|
50
|
66
|
|
|
318
|
if ($lazy && $find_pref && $level >= $#{$key}) { |
|
|
0
|
|
33
|
|
|
0
|
|
|
354
|
0
|
|
|
|
|
0
|
return $keys[$pos-1]; |
|
355
|
|
|
|
|
|
|
}; |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Stop processing |
|
358
|
150
|
100
|
|
|
|
324
|
return if $lazy; |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
# There is a stop value defined and no primary exists |
|
361
|
141
|
100
|
100
|
|
|
415
|
push @keys, '.' if $dict->{'.'} && !$keys[0]; |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# Lazy load further keys |
|
364
|
|
|
|
|
|
|
# Add preferred keys |
|
365
|
141
|
100
|
|
|
|
280
|
if ($dict->{'_'}) { |
|
366
|
85
|
|
|
|
|
224
|
my @matches = _get_pref_keys($c, $dict->{'_'}, $stash); |
|
367
|
85
|
100
|
|
|
|
204
|
if ($matches[0]) { |
|
368
|
75
|
|
|
|
|
110
|
if (DEBUG) { |
|
369
|
|
|
|
|
|
|
_debug( |
|
370
|
|
|
|
|
|
|
$c->app, |
|
371
|
|
|
|
|
|
|
qq![LOOKUP] But there are preferred keys "@matches"! |
|
372
|
|
|
|
|
|
|
); |
|
373
|
|
|
|
|
|
|
}; |
|
374
|
75
|
|
|
|
|
196
|
push @keys, @matches; |
|
375
|
|
|
|
|
|
|
}; |
|
376
|
|
|
|
|
|
|
}; |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Add default key |
|
379
|
141
|
100
|
|
|
|
362
|
if ($dict->{'-'}) { |
|
380
|
74
|
|
|
|
|
142
|
my $match = $dict->{'-'}; |
|
381
|
74
|
|
|
|
|
103
|
if (DEBUG) { |
|
382
|
|
|
|
|
|
|
_debug($c->app, qq![LOOKUP] But there is a default key "$match"!); |
|
383
|
|
|
|
|
|
|
}; |
|
384
|
74
|
50
|
|
|
|
287
|
push @keys, $match if $match; |
|
385
|
|
|
|
|
|
|
}; |
|
386
|
|
|
|
|
|
|
|
|
387
|
141
|
100
|
|
|
|
484
|
return unless $keys[$pos]; |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# There may be items set multiple times |
|
390
|
95
|
|
|
|
|
657
|
@keys = uniq @keys; |
|
391
|
|
|
|
|
|
|
|
|
392
|
95
|
|
|
|
|
205
|
_debug($c->app, qq![LOOKUP] Check non-manual keys "@keys"!) if DEBUG; |
|
393
|
|
|
|
|
|
|
|
|
394
|
95
|
|
|
|
|
153
|
$lazy = 1; |
|
395
|
|
|
|
|
|
|
}; |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# Key has a match |
|
398
|
427
|
100
|
|
|
|
1103
|
if (my $match = $dict->{$keys[$pos]}) { |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# Debug information |
|
401
|
343
|
|
|
|
|
513
|
if (DEBUG) { |
|
402
|
|
|
|
|
|
|
_debug( |
|
403
|
|
|
|
|
|
|
$c->app, |
|
404
|
|
|
|
|
|
|
qq![LOOKUP] Found entry for "$keys[$pos]" on input level [$level]! |
|
405
|
|
|
|
|
|
|
); |
|
406
|
|
|
|
|
|
|
}; |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# The match is final |
|
409
|
343
|
100
|
100
|
|
|
2459
|
if ((!ref($match) || ref($match) eq 'SCALAR' || ref($match) eq 'CODE') && !$find_pref) { |
|
|
|
100
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# Everything is cosumed - fine |
|
412
|
112
|
50
|
|
|
|
169
|
if ($level >= $#{$key}) { |
|
|
112
|
|
|
|
|
293
|
|
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# Value is scalar |
|
415
|
112
|
100
|
|
|
|
299
|
if (ref $match eq 'SCALAR') { |
|
|
|
100
|
|
|
|
|
|
|
416
|
83
|
|
|
|
|
145
|
if (DEBUG) { |
|
417
|
|
|
|
|
|
|
_debug( |
|
418
|
|
|
|
|
|
|
$c->app, |
|
419
|
|
|
|
|
|
|
qq![LOOKUP] Found scalar value "$$match"! |
|
420
|
|
|
|
|
|
|
); |
|
421
|
|
|
|
|
|
|
}; |
|
422
|
83
|
|
|
|
|
312
|
return $$match; |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# Value is a subroutine |
|
426
|
|
|
|
|
|
|
elsif (ref $match eq 'CODE') { |
|
427
|
2
|
|
|
|
|
9
|
my $value = $match->($c, %$stash); |
|
428
|
2
|
|
|
|
|
16
|
if (DEBUG) { |
|
429
|
|
|
|
|
|
|
_debug( |
|
430
|
|
|
|
|
|
|
$c->app, |
|
431
|
|
|
|
|
|
|
qq![LOOKUP] Found subroutine value as "$value"! |
|
432
|
|
|
|
|
|
|
); |
|
433
|
|
|
|
|
|
|
}; |
|
434
|
2
|
|
|
|
|
20
|
return $value; |
|
435
|
|
|
|
|
|
|
}; |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
# Value is a template |
|
438
|
27
|
|
|
|
|
140
|
my $value = $c->render_to_string(inline => $match, %$stash); |
|
439
|
27
|
50
|
|
|
|
21472
|
chomp($value) unless delete $stash->{no_trim}; |
|
440
|
27
|
|
|
|
|
2364
|
if (DEBUG) { |
|
441
|
|
|
|
|
|
|
_debug( |
|
442
|
|
|
|
|
|
|
$c->app, |
|
443
|
|
|
|
|
|
|
qq![LOOKUP] Found template value as "$value"! |
|
444
|
|
|
|
|
|
|
); |
|
445
|
|
|
|
|
|
|
}; |
|
446
|
27
|
|
|
|
|
133
|
return $value; |
|
447
|
|
|
|
|
|
|
}; |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
# Check another path |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Get the relevant key if everything is consumed |
|
453
|
6
|
|
|
|
|
17
|
elsif (ref($match) && $find_pref && $level > $#{$key}) { |
|
454
|
|
|
|
|
|
|
|
|
455
|
4
|
|
|
|
|
5
|
if (DEBUG) { |
|
456
|
|
|
|
|
|
|
_debug( |
|
457
|
|
|
|
|
|
|
$c->app, |
|
458
|
|
|
|
|
|
|
'[PREF] Found key "' . $keys[$pos] . '"' |
|
459
|
|
|
|
|
|
|
); |
|
460
|
|
|
|
|
|
|
}; |
|
461
|
|
|
|
|
|
|
|
|
462
|
4
|
|
|
|
|
14
|
return $keys[$pos]; |
|
463
|
|
|
|
|
|
|
} |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# No final match found - go on |
|
466
|
|
|
|
|
|
|
else { |
|
467
|
|
|
|
|
|
|
|
|
468
|
227
|
|
|
|
|
332
|
my $level_up = $level; |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
# If the primary key was consumed or not given, level up |
|
471
|
227
|
100
|
100
|
|
|
596
|
if (!$pos || !$key->[$level]) { |
|
472
|
173
|
|
|
|
|
255
|
$level_up++; |
|
473
|
173
|
|
|
|
|
260
|
if (DEBUG) { |
|
474
|
|
|
|
|
|
|
_debug($c->app, "[LOOKUP] Forward to input level [$level_up]"); |
|
475
|
|
|
|
|
|
|
}; |
|
476
|
|
|
|
|
|
|
}; |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# Call lookup recursively |
|
479
|
227
|
|
|
|
|
590
|
my $found = _lookup( |
|
480
|
|
|
|
|
|
|
$c, $stash, $match, $key, $level_up, $find_pref |
|
481
|
|
|
|
|
|
|
); |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# Found something |
|
484
|
227
|
100
|
|
|
|
1520
|
return $found if $found; |
|
485
|
|
|
|
|
|
|
}; |
|
486
|
|
|
|
|
|
|
}; |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# Get next key |
|
489
|
131
|
|
|
|
|
215
|
$pos++; |
|
490
|
131
|
|
|
|
|
185
|
if (DEBUG) { |
|
491
|
|
|
|
|
|
|
_debug($c->app, "[LOOKUP] Forward to next key at position $pos"); |
|
492
|
|
|
|
|
|
|
}; |
|
493
|
|
|
|
|
|
|
}; |
|
494
|
|
|
|
|
|
|
}; |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# Debug messages |
|
498
|
|
|
|
|
|
|
sub _debug { |
|
499
|
4
|
|
|
4
|
|
26
|
my ($app, $msg) = @_; |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# If the value is 2 - debug to stderr |
|
502
|
4
|
|
|
|
|
7
|
if (DEBUG == 2) { |
|
503
|
|
|
|
|
|
|
print STDERR "$msg\n"; |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
# Otherwise debug to log |
|
507
|
|
|
|
|
|
|
else { |
|
508
|
4
|
|
|
|
|
19
|
$app->log->debug($msg); |
|
509
|
|
|
|
|
|
|
} |
|
510
|
|
|
|
|
|
|
}; |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# Return preferred keys |
|
514
|
|
|
|
|
|
|
sub _get_pref_keys { |
|
515
|
85
|
|
|
85
|
|
175
|
my ($c, $index, $stash) = @_; |
|
516
|
|
|
|
|
|
|
|
|
517
|
85
|
50
|
|
|
|
191
|
return unless $index; |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
# Preferred key is a template |
|
520
|
85
|
100
|
33
|
|
|
325
|
unless (ref $index) { |
|
|
|
100
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
|
|
522
|
2
|
|
|
|
|
16
|
my $key = $c->render_to_string(inline => $index, %$stash); |
|
523
|
2
|
50
|
|
|
|
3587
|
chomp($key) unless delete $stash->{no_trim}; |
|
524
|
2
|
|
|
|
|
81
|
return $key; |
|
525
|
|
|
|
|
|
|
} |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# Preferred key is a subroutine |
|
528
|
0
|
|
|
|
|
0
|
elsif (ref $index eq 'CODE') { |
|
529
|
|
|
|
|
|
|
|
|
530
|
50
|
|
|
|
|
217
|
local $_ = $c->localize; |
|
531
|
50
|
|
|
|
|
940
|
my $pref = $index->($c); |
|
532
|
50
|
100
|
|
|
|
435
|
return ref $pref ? @$pref : ($pref); |
|
533
|
|
|
|
|
|
|
} |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# Preferred key is an array |
|
536
|
|
|
|
|
|
|
elsif (ref $index eq 'ARRAY') { |
|
537
|
|
|
|
|
|
|
return @{$index}; |
|
538
|
|
|
|
|
|
|
}; |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# No preferred keys or invalid notation |
|
541
|
0
|
|
|
|
|
|
return; |
|
542
|
|
|
|
|
|
|
}; |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
1; |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
__END__ |