package Config::General::Interpolated; $Config::General::Interpolated::VERSION = "1.4"; use strict; use Carp; use Config::General; use Exporter (); # Import stuff from Config::General use vars qw(@ISA @EXPORT); @ISA = qw(Config::General Exporter); @EXPORT=qw(_set_regex _vars); sub new { # # overwrite new() with our own version # and call the parent class new() # croak "Deprecated method Config::General::Interpolated::new() called.\n" ."Use Config::General::new() instead and set the -InterPolateVars flag.\n"; } sub _set_regex { # # set the regex for finding vars # # the following regex is provided by Autrijus Tang # , and I made some modifications. # thanx, autrijus. :) my $regex = qr{ (^|[^\\]) # can be the beginning of the line # but can't begin with a '\' \$ # dollar sign (\{)? # $1: optional opening curly ([a-zA-Z_]\w*) # $2: capturing variable name ( ?(2) # $3: if there's the opening curly... \} # ... match closing curly ) }x; return $regex; } sub _vars { my ($this, $config, $stack) = @_; my %varstack; $stack = {} unless defined $stack; # make sure $stack is assigned. # collect values that don't need to be substituted first while (my ($key, $value) = each %{$config}) { $varstack{$key} = $value unless ref($value) or $value =~ /$this->{regex}/; } my $sub_interpolate = sub { my ($value) = @_; # this is a scalar if ($value =~ m/^'/ and $value =~ m/'$/) { # single-quote, remove it and don't do variable interpolation $value =~ s/^'//; $value =~ s/'$//; } else { $value =~ s{$this->{regex}}{ my $con = $1; my $var = $3; my $v = $varstack{$var} || $stack->{$var}; if (defined $v) { $con . $v; } else { croak "Use of uninitialized variable \$" . $var . "\n"; } }egx; } return $value; }; # interpolate variables while (my ($key, $value) = each %{$config}) { if (my $reftype = ref($value)) { next unless $reftype eq 'ARRAY'; # we encounter multiple options @{$value} = map { $sub_interpolate->($_) } @{$value}; } else { $value = $sub_interpolate->($value); $config->{$key} = $value; $varstack{$key} = $value; } } # traverse the hierarchy part while (my ($key, $value) = each %{$config}) { # this is not a scalar recursive call to myself if (ref($value) eq 'HASH') { # called via Gonfig::General procedural _vars($this, $value, {%{$stack}, %varstack}); } } return $config; } 1; __END__ =head1 NAME Config::General::Interpolated - Parse variables within Config files =head1 SYNOPSIS use Config::General; $conf = new Config::General( -CinfigFile => 'configfile', -InterPolateVars => 1 ); =head1 DESCRIPTION This is an internal module which makes it possible to interpolate perl style variables in your config file (i.e. C<$variable> or C<${variable}>). Normally you don't call it directly. =head1 VARIABLES Variables can be defined everywhere in the config and can be used afterwards. If you define a variable inside a block or a named block then it is only visible within this block or within blocks which are defined inside this block. Well - let's take a look to an example: # sample config which uses variables basedir = /opt/ora user = t_space sys = unix instance = INTERN owner = $user # "t_space" logdir = $basedir/log # "/opt/ora/log" sys = macos misc1 = ${sys}_${instance} # macos_INTERN misc2 = $user # "t_space"
This will result in the following structure: { 'basedir' => '/opt/ora', 'user' => 't_space' 'sys' => 'unix', 'table' => { 'intern' => { 'sys' => 'macos', 'logdir' => '/opt/ora/log', 'instance' => 'INTERN', 'owner' => 't_space', 'procs' => { 'misc1' => 'macos_INTERN', 'misc2' => 't_space' } } } As you can see, the variable B has been defined twice. Inside the block a variable ${sys} has been used, which then were interpolated into the value of B defined inside the block, not the sys variable one level above. If sys were not defined inside the
block then the "global" variable B would have been used instead with the value of "unix". Variables inside double quotes will be interpolated, but variables inside single quotes will B interpolated. This is the same behavior as you know of perl itself. In addition you can surround variable names with curly braces to avoid misinterpretation by the parser. =head1 SEE ALSO L =head1 AUTHORS Thomas Linden Autrijus Tang Wei-Hon Chen =head1 COPYRIGHT Copyright 2001 by Wei-Hon Chen Eplasmaball@pchome.com.twE. Copyright 2002 by Thomas Linden . This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =head1 VERSION 1.4 =cut