http://qs321.pair.com?node_id=1144392


in reply to Re^2: reference to an undefined key
in thread reference to an undefined key

You're asking if there's any module for dealing with resolving templates. I'm sure there are, but none offhand that I've used extensively. (Did you try a search of cpan?)

As to the inherent dangers of elaborating things as you suggest, the one that comes to mind is -- you'd better only make use of key/value pairs in the order they're resolved, or you may come up against infinite recursion. For example:

[ConfigDirs] A = /some/dir B = /_#C#_/DeeperDir C = /_#B#_/EvenDeeperDir

which would never fully expand (B references C, which references B again). So you wouldn't want to necessarily make that into a hash; a list would be more appropriate I think, as you could throw an error any time you came across a variable which hadn't previously been defined.

Here's an example that uses an array (hardwired, but you could read it in from a config file), and then creates a hash of resolved parameters:

#!/usr/bin/perl ############### ## Libraries ## ############### use strict; use warnings; use feature qw{ say }; ################## ## User-defined ## ################## # Define what makes a "template" variable my $re_template = qr/_#([^#]+)#_/; # The result of what you read from your config file, perhaps. # Note that it's an ARRAY, since we'd like to prevent unintentional # recursion (we should resolve template variables in the order in # which they're seen). my $a_params = [ [ 'A' => '/some/dir' ], [ 'B' => '/_#A#_/DeeperDir' ], [ 'C' => '/_#B#_/EvenDeeperDir' ], ]; ################## ## Main program ## ################## show_params($a_params, "[Before resolution]"); my $h_resolved = resolve_templates($a_params); show_params($h_resolved, "[After resolution]"); ################# ## Subroutines ## ################# sub resolve_templates { my ($a_params) = @_; my $h_resolved = { }; for (my $i = 0; $i < @$a_params; $i++) { my $idx = $i + 1; my $a_keyval = $a_params->[$i]; my ($key, $tmpl) = @$a_keyval; my $orig = $tmpl; while ($tmpl =~ /$re_template/) { my $ref = $1; my $refval = $h_resolved->{$ref}; defined($refval) or die "Undefined ref '$ref' in '$orig'\n +"; $tmpl =~ s/$re_template/$refval/g; } $h_resolved->{$key} = $tmpl; } return $h_resolved; } sub show_params { my ($a_params, $msg) = @_; $msg ||= "Parameters:"; say "-" x 79; say $msg; say "-" x 79; if (ref $a_params eq 'HASH') { # If a HASH was passed, turn it into an ARRAY my $h_params = $a_params; my @keys = sort { $a cmp $b } keys %$h_params; $a_params = [ map { [ $_ => $h_params->{$_} ] } @keys ]; } foreach my $a_keyval (@$a_params) { my ($key, $val) = @$a_keyval; my $text = "Parameter '$key' "; $text .= "." x (32 - length($text)); $text .= " '$val'"; say $text; } say ""; }

And here its output:

---------------------------------------------------------------------- +--------- [Before resolution] ---------------------------------------------------------------------- +--------- Parameter 'A' .................. '/some/dir' Parameter 'B' .................. '/_#A#_/DeeperDir' Parameter 'C' .................. '/_#B#_/EvenDeeperDir' ---------------------------------------------------------------------- +--------- [After resolution] ---------------------------------------------------------------------- +--------- Parameter 'A' .................. '/some/dir' Parameter 'B' .................. '//some/dir/DeeperDir' Parameter 'C' .................. '///some/dir/DeeperDir/EvenDeeperDir'

say  substr+lc crypt(qw $i3 SI$),4,5