@@ -4,7 +4,7 @@ use 5.008000;
4
4
use strict;
5
5
use warnings;
6
6
7
- our $VERSION = ' 0.20 ' ;
7
+ our $VERSION = ' 0.21_01 ' ;
8
8
9
9
use File::Spec;
10
10
use YAML::XS qw( LoadFile ) ;
@@ -94,7 +94,7 @@ sub load {
94
94
$self -> {_config } = $self -> {_merger }-> merge( $self -> {_config },
95
95
{ ENV => {%ENV } } );
96
96
}
97
- $self -> _process_tree( $self -> {_config } );
97
+ $self -> _process_tree( $self -> {_config }, [] );
98
98
99
99
$self -> {_vars } = {};
100
100
$self -> {_seen_nodes } = {};
@@ -194,10 +194,11 @@ sub _load_json {
194
194
195
195
sub _process_tree {
196
196
my $self = shift ;
197
+ my $ancs = pop ;
197
198
198
199
return if readonly( $_ [0] );
199
200
200
- $_ [0] = $self -> _process_node( $_ [0] );
201
+ $_ [0] = $self -> _process_node( $_ [0], $ancs );
201
202
202
203
if ( my $node_addr = refaddr( $_ [0] ) ) {
203
204
return if $self -> {_seen_nodes }{$node_addr };
@@ -207,12 +208,12 @@ sub _process_tree {
207
208
208
209
if ( ref ( $_ [0] ) eq ' HASH' ) {
209
210
foreach ( values %{ $_ [0] } ) {
210
- $self -> _process_tree($_ );
211
+ $self -> _process_tree( $_ , [ $_ [0], @{ $ancs } ] );
211
212
}
212
213
}
213
214
elsif ( ref ( $_ [0] ) eq ' ARRAY' ) {
214
215
foreach ( @{ $_ [0] } ) {
215
- $self -> _process_tree($_ );
216
+ $self -> _process_tree( $_ , [ $_ [0], @{ $ancs } ] );
216
217
}
217
218
}
218
219
@@ -222,30 +223,31 @@ sub _process_tree {
222
223
sub _process_node {
223
224
my $self = shift ;
224
225
my $node = shift ;
226
+ my $ancs = shift ;
225
227
226
228
return unless defined $node ;
227
229
228
230
if ( !ref ($node ) && $self -> {interpolate_variables } ) {
229
231
$node =~ s /\$ ((\$ ?)\{ ([^\} ]*)\} )/
230
- $2 ? $1 : ( $self ->_resolve_var( $3 ) || '' )/ ge ;
232
+ $2 ? $1 : ( $self ->_resolve_var( $3 , $ancs ) || '' )/ ge ;
231
233
}
232
234
elsif ( ref ($node ) eq ' HASH' && $self -> {process_directives } ) {
233
235
if ( defined $node -> {var } ) {
234
- $node = $self -> _resolve_var( $node -> {var } );
236
+ $node = $self -> _resolve_var( $node -> {var }, $ancs );
235
237
}
236
238
elsif ( defined $node -> {include } ) {
237
239
$node = $self -> _build_tree( $node -> {include } );
238
240
}
239
241
else {
240
242
if ( defined $node -> {underlay } ) {
241
243
my $layer = delete $node -> {underlay };
242
- $layer = $self -> _process_layer($layer );
244
+ $layer = $self -> _process_layer( $layer , $ancs );
243
245
$node = $self -> {_merger }-> merge( $layer , $node );
244
246
}
245
247
246
248
if ( defined $node -> {overlay } ) {
247
249
my $layer = delete $node -> {overlay };
248
- $layer = $self -> _process_layer($layer );
250
+ $layer = $self -> _process_layer( $layer , $ancs );
249
251
$node = $self -> {_merger }-> merge( $node , $layer );
250
252
}
251
253
}
@@ -257,15 +259,16 @@ sub _process_node {
257
259
sub _process_layer {
258
260
my $self = shift ;
259
261
my $layer = shift ;
262
+ my $ancs = shift ;
260
263
261
264
if ( ref ($layer ) eq ' HASH' ) {
262
- $layer = $self -> _process_node( $layer );
265
+ $layer = $self -> _process_node( $layer , $ancs );
263
266
}
264
267
elsif ( ref ($layer ) eq ' ARRAY' ) {
265
268
my $new_layer = {};
266
269
267
270
foreach my $node ( @{$layer } ) {
268
- $node = $self -> _process_node( $node );
271
+ $node = $self -> _process_node( $node , $ancs );
269
272
$new_layer = $self -> {_merger }-> merge( $new_layer , $node );
270
273
}
271
274
@@ -276,63 +279,113 @@ sub _process_layer {
276
279
}
277
280
278
281
sub _resolve_var {
279
- my $self = shift ;
280
- my $var_name = shift ;
281
-
282
- my $vars = $self -> {_vars };
283
-
284
- unless ( defined $vars -> {$var_name } ) {
285
- my @tokens = split ( / \. / , $var_name );
286
- my $pointer = $self -> {_config };
282
+ my $self = shift ;
283
+ my $name = shift ;
284
+ my $ancs = shift ;
287
285
288
- my $value ;
286
+ if ( $name =~ m / ^\. / ) {
287
+ my @tokens = split ( / \. / , $name );
288
+ my $anc_index = -1;
289
289
290
290
while (1) {
291
- my $token = shift @ tokens ;
291
+ my $token = $ tokens[0] ;
292
292
$token =~ s / ^\s +// ;
293
293
$token =~ s /\s +$// ;
294
294
295
- if ( ref ($pointer ) eq ' HASH' ) {
296
- last unless defined $pointer -> {$token };
295
+ last if length ($token ) > 0;
297
296
298
- if ( ! @tokens ) {
299
- $value = $self -> _process_node( $pointer -> { $token } ) ;
300
- $pointer -> { $token } = $value ;
297
+ shift @tokens ;
298
+ $anc_index ++ ;
299
+ }
301
300
302
- last ;
303
- }
301
+ my $node = $ancs -> [$anc_index ];
304
302
305
- last unless ref ( $pointer -> {$token } );
303
+ my $value = eval {
304
+ $self -> _fetch_value( $node , \@tokens , $ancs );
305
+ };
306
306
307
- $pointer = $pointer -> {$token };
308
- }
309
- else { # ARRAY
310
- if ( $token =~ m /\D / ) {
311
- die " Argument \" $token \" isn't numeric in array element:"
312
- . " $var_name \n " ;
313
- }
307
+ if ($@ ) {
308
+ chomp $@ ;
309
+ die qq{ Can't resolve variable "$name "; $@ \n } ;
310
+ }
314
311
315
- last unless defined $pointer -> [$token ];
312
+ return $value ;
313
+ }
314
+
315
+ my $vars = $self -> {_vars };
316
316
317
- if ( !@tokens ) {
318
- $value = $self -> _process_node( $pointer -> [$token ] );
319
- $pointer -> [$token ] = $value ;
317
+ unless ( defined $vars -> {$name } ) {
318
+ my @tokens = split ( / \. / , $name );
320
319
321
- last ;
322
- }
320
+ my $value = eval {
321
+ $self -> _fetch_value( $self -> {_config }, \@tokens , $ancs );
322
+ };
323
323
324
- last unless ref ( $pointer -> [$token ] );
324
+ if ($@ ) {
325
+ chomp $@ ;
326
+ die qq{ Can't resolve variable "$name "; $@ \n } ;
327
+ }
328
+
329
+ $vars -> {$name } = $value ;
330
+ }
325
331
326
- $pointer = $pointer -> [$token ];
332
+ return $vars -> {$name };
333
+ }
334
+
335
+ # ###
336
+ sub _fetch_value {
337
+ my $self = shift ;
338
+ my $node = shift ;
339
+ my $tokens = shift ;
340
+ my $ancs = shift ;
341
+
342
+ my $value ;
343
+ my @anc_stack = @{$ancs };
344
+
345
+ while (1) {
346
+ my $token = shift @{$tokens };
347
+ $token =~ s / ^\s +// ;
348
+ $token =~ s /\s +$// ;
349
+
350
+ if ( ref ($node ) eq ' HASH' ) {
351
+ last unless defined $node -> {$token };
352
+
353
+ unshift ( @anc_stack , $node );
354
+
355
+ unless ( @{$tokens } ) {
356
+ $value = $self -> _process_node( $node -> {$token }, \@anc_stack );
357
+ $node -> {$token } = $value ;
358
+
359
+ last ;
327
360
}
361
+
362
+ last unless ref ( $node -> {$token } );
363
+
364
+ $node = $node -> {$token };
328
365
}
366
+ else { # ARRAY
367
+ if ( $token =~ m /\D / ) {
368
+ die qq{ Argument "$token " isn't numeric in array element.\n } ;
369
+ }
370
+
371
+ last unless defined $node -> [$token ];
372
+
373
+ unshift ( @anc_stack , $node );
374
+
375
+ unless ( @{$tokens } ) {
376
+ $value = $self -> _process_node( $node -> [$token ], \@anc_stack );
377
+ $node -> [$token ] = $value ;
378
+
379
+ last ;
380
+ }
381
+
382
+ last unless ref ( $node -> [$token ] );
329
383
330
- if ( defined $value ) {
331
- $vars -> {$var_name } = $value ;
384
+ $node = $node -> [$token ];
332
385
}
333
386
}
334
387
335
- return $vars -> { $var_name } ;
388
+ return $value ;
336
389
}
337
390
338
391
1;
0 commit comments