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
|