Skip to content

Commit a37ed0e

Browse files
committed
Added resolving of relative variable names
1 parent 8cb07bb commit a37ed0e

File tree

3 files changed

+103
-50
lines changed

3 files changed

+103
-50
lines changed

README

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Config-Processor version 0.20
1+
Config-Processor version 0.21_01
22
=============================
33

44
INSTALLATION
@@ -24,7 +24,7 @@ Eugene Ponizovsky, <[email protected]>
2424

2525
COPYRIGHT AND LICENSE
2626

27-
Copyright (c) 2016, Eugene Ponizovsky, <[email protected]>.
27+
Copyright (c) 2016-2017, Eugene Ponizovsky, <[email protected]>.
2828
All rights reserved.
2929

3030
This module is free software; you can redistribute it and/or modify it under

lib/Config/Processor.pm

Lines changed: 100 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use 5.008000;
44
use strict;
55
use warnings;
66

7-
our $VERSION = '0.20';
7+
our $VERSION = '0.21_01';
88

99
use File::Spec;
1010
use YAML::XS qw( LoadFile );
@@ -94,7 +94,7 @@ sub load {
9494
$self->{_config} = $self->{_merger}->merge( $self->{_config},
9595
{ ENV => {%ENV} } );
9696
}
97-
$self->_process_tree( $self->{_config} );
97+
$self->_process_tree( $self->{_config}, [] );
9898

9999
$self->{_vars} = {};
100100
$self->{_seen_nodes} = {};
@@ -194,10 +194,11 @@ sub _load_json {
194194

195195
sub _process_tree {
196196
my $self = shift;
197+
my $ancs = pop;
197198

198199
return if readonly( $_[0] );
199200

200-
$_[0] = $self->_process_node( $_[0] );
201+
$_[0] = $self->_process_node( $_[0], $ancs );
201202

202203
if ( my $node_addr = refaddr( $_[0] ) ) {
203204
return if $self->{_seen_nodes}{$node_addr};
@@ -207,12 +208,12 @@ sub _process_tree {
207208

208209
if ( ref( $_[0] ) eq 'HASH' ) {
209210
foreach ( values %{ $_[0] } ) {
210-
$self->_process_tree($_);
211+
$self->_process_tree( $_, [ $_[0], @{$ancs} ] );
211212
}
212213
}
213214
elsif ( ref( $_[0] ) eq 'ARRAY' ) {
214215
foreach ( @{ $_[0] } ) {
215-
$self->_process_tree($_);
216+
$self->_process_tree( $_, [ $_[0], @{$ancs} ] );
216217
}
217218
}
218219

@@ -222,30 +223,31 @@ sub _process_tree {
222223
sub _process_node {
223224
my $self = shift;
224225
my $node = shift;
226+
my $ancs = shift;
225227

226228
return unless defined $node;
227229

228230
if ( !ref($node) && $self->{interpolate_variables} ) {
229231
$node =~ s/\$((\$?)\{([^\}]*)\})/
230-
$2 ? $1 : ( $self->_resolve_var( $3 ) || '' )/ge;
232+
$2 ? $1 : ( $self->_resolve_var( $3, $ancs ) || '' )/ge;
231233
}
232234
elsif ( ref($node) eq 'HASH' && $self->{process_directives} ) {
233235
if ( defined $node->{var} ) {
234-
$node = $self->_resolve_var( $node->{var} );
236+
$node = $self->_resolve_var( $node->{var}, $ancs );
235237
}
236238
elsif ( defined $node->{include} ) {
237239
$node = $self->_build_tree( $node->{include} );
238240
}
239241
else {
240242
if ( defined $node->{underlay} ) {
241243
my $layer = delete $node->{underlay};
242-
$layer = $self->_process_layer($layer);
244+
$layer = $self->_process_layer( $layer, $ancs );
243245
$node = $self->{_merger}->merge( $layer, $node );
244246
}
245247

246248
if ( defined $node->{overlay} ) {
247249
my $layer = delete $node->{overlay};
248-
$layer = $self->_process_layer($layer);
250+
$layer = $self->_process_layer( $layer, $ancs );
249251
$node = $self->{_merger}->merge( $node, $layer );
250252
}
251253
}
@@ -257,15 +259,16 @@ sub _process_node {
257259
sub _process_layer {
258260
my $self = shift;
259261
my $layer = shift;
262+
my $ancs = shift;
260263

261264
if ( ref($layer) eq 'HASH' ) {
262-
$layer = $self->_process_node( $layer );
265+
$layer = $self->_process_node( $layer, $ancs );
263266
}
264267
elsif ( ref($layer) eq 'ARRAY' ) {
265268
my $new_layer = {};
266269

267270
foreach my $node ( @{$layer} ) {
268-
$node = $self->_process_node( $node );
271+
$node = $self->_process_node( $node, $ancs );
269272
$new_layer = $self->{_merger}->merge( $new_layer, $node );
270273
}
271274

@@ -276,63 +279,113 @@ sub _process_layer {
276279
}
277280

278281
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;
287285

288-
my $value;
286+
if ( $name =~ m/^\./ ) {
287+
my @tokens = split( /\./, $name );
288+
my $anc_index = -1;
289289

290290
while (1) {
291-
my $token = shift @tokens;
291+
my $token = $tokens[0];
292292
$token =~ s/^\s+//;
293293
$token =~ s/\s+$//;
294294

295-
if ( ref($pointer) eq 'HASH' ) {
296-
last unless defined $pointer->{$token};
295+
last if length($token) > 0;
297296

298-
if ( !@tokens ) {
299-
$value = $self->_process_node( $pointer->{$token} );
300-
$pointer->{$token} = $value;
297+
shift @tokens;
298+
$anc_index++;
299+
}
301300

302-
last;
303-
}
301+
my $node = $ancs->[$anc_index];
304302

305-
last unless ref( $pointer->{$token} );
303+
my $value = eval {
304+
$self->_fetch_value( $node, \@tokens, $ancs );
305+
};
306306

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+
}
314311

315-
last unless defined $pointer->[$token];
312+
return $value;
313+
}
314+
315+
my $vars = $self->{_vars};
316316

317-
if ( !@tokens ) {
318-
$value = $self->_process_node( $pointer->[$token] );
319-
$pointer->[$token] = $value;
317+
unless ( defined $vars->{$name} ) {
318+
my @tokens = split( /\./, $name );
320319

321-
last;
322-
}
320+
my $value = eval {
321+
$self->_fetch_value( $self->{_config}, \@tokens, $ancs );
322+
};
323323

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+
}
325331

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;
327360
}
361+
362+
last unless ref( $node->{$token} );
363+
364+
$node = $node->{$token};
328365
}
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] );
329383

330-
if ( defined $value ) {
331-
$vars->{$var_name} = $value;
384+
$node = $node->[$token];
332385
}
333386
}
334387

335-
return $vars->{$var_name};
388+
return $value;
336389
}
337390

338391
1;

t/03-exceptions.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ sub t_invalid_array_element_index {
8080
}
8181
);
8282
},
83-
qr/^Argument \"param4_1\" isn't numeric in array element: foo\.param4\.param4_1/,
83+
qr/^Can't resolve variable "foo\.param4\.param4_1";/,
8484
'invalid array element index'
8585
);
8686

0 commit comments

Comments
 (0)