iaw4 has asked for the wisdom of the Perl Monks concerning the following question:

dear monks: I want to work with a template that has access to all my perl variables that are of the form '\$\w+', but nothing else. I understand that there are templating systems that do this more professionally, but I want it quick-and-dirty. one-liners are appealing!

now, the below code fragment works, except when a variable is not defined. so how do I handle undefined variables?

use warnings FATAL => qw{ uninitialized }; my $abc = "ABC"; my $def = "DEF"; ## no $ghi is defined. my $funnystring= ' hello $abc and $def and $ghi'; $funnystring =~ s/(\$\w+)/"defined($1) ? $1 : 'unknown $1'"/gee; print $funnystring;
(I could turn the warning off, but then I lose the flexibility of writing something that describes the undefined variable.) /iaw
  • Comment on super-simple regex-based template eval --- handling undefined substitutions
  • Download Code

Replies are listed 'Best First'.
Re: super-simple regex-based template eval --- handling undefined substitutions
by Kenosis (Priest) on Sep 15, 2012 at 22:02 UTC

    Does the following help?

    use Modern::Perl; use warnings FATAL => qw{ uninitialized }; my $abc = "ABC"; my $def = "DEF"; ## no $ghi is defined. my $jkl = 0; my $funnystring = 'hello $abc and $def and $ghi and $jkl'; $funnystring =~ s/(\$\w+)/defined eval $1 ? eval $1 : "unknown $1" /ge +; print $funnystring;

    Output:

    hello ABC and DEF and unknown $ghi and 0

    Update: Changed from single to double quotes (i.e., "unknown $1") in the ternary operator to show unknown $ghi in output instead of unknown $1.

      yes, it does help. thanks. of course, it would be nicer if unknown $1 were to become 'unknown $ghi'. but it's a great one-liner, nonetheless.

        Using double quotes in the ternary operator will achieve this. Have updated the code to do this...

Re: super-simple regex-based template eval --- handling undefined substitutions
by AnomalousMonk (Archbishop) on Sep 15, 2012 at 22:05 UTC
    >perl -wMstrict -le "my ($w, $x, $y) = qw(YUU EKS); ;; my $scalar = qr{ \$ \s* (?: { \s* \w+ } | \w+ ) }xms; ;; my $interpol = q{hi from '$w' and ${x}also $y and $z too}; ;; $interpol =~ s{ ($scalar) } { no warnings qw(ambiguous); my $e = eval qq{$1}; $@ ? qq{[['$1' non-existant]]} : ! defined($e) ? qq{[['$1' undefined]]} : $e; }xmseg; ;; print qq{'$interpol'}; " 'hi from 'YUU' and EKSalso [['$y' undefined]] and [['$z' non-existant] +] too'

    Update: I like this one better: no no warnings, and it supports  \$ escaped dollars and all forms of scalars I know of, which are normalized to a canonical form (sorry for any pesky wraparound, which I tried to fix this up a bit) (tested under 5.8.9 and 5.14.2):

    >perl -wMstrict -le "my ($w, $x, $y) = qw(YUU EKS); ;; my $interpol = q{hi \$w from '$w' and ${x}also $y and $z too} . qq{\n} . q{'$x' '$ x' '$ x' '${x}' '${ x}' '${ x}'} . qq{\n} . q{'$y' '$ y' '$ y' '${y}' '${ y}' '${ y}'} . qq{\n} . q{'$z' '$ z' '$ z' '${z}' '${ z}' '${ z}'} . qq{\n} ; print qq{$interpol}; ;; my $scalar = qr{ (?<! \\) \$ \s* (?: { \s* (\w+) } | (\w+) ) }xms; $interpol =~ s{ $scalar } { my $s = qq{\$$^N}; my $e = eval $s; $@ ? qq{[['$s' non-existant]]} : ! defined($e) ? qq{[['$s' undefined]]} : $e; }xmseg; ;; print qq{'$interpol'}; " hi \$w from '$w' and ${x}also $y and $z too '$x' '$ x' '$ x' '${x}' '${ x}' '${ x}' '$y' '$ y' '$ y' '${y}' '${ y}' '${ y}' '$z' '$ z' '$ z' '${z}' '${ z}' '${ z}' 'hi \$w from 'YUU' and EKSalso [['$y' undefined]] and [['$z' non-exist +ant]] too 'EKS' 'EKS' 'EKS' 'EKS' 'EKS' 'EKS' '[['$y' undefined]]' '[['$y' undefined]]' '[['$y' undefined]]' '[['$y' undefined]]' '[['$y' undefined]]' '[['$y' undefined]]' '[['$z' non-existant]]' '[['$z' non-existant]]' '[['$z' non-existant]]' '[['$z' non-existant]]' '[['$z' non-existant]]' '[['$z' non-existant]]' '
      thank you. this does the job perfectly.