I'm asking this question because I finally solved a problem that I have been trying to find a technique for in a number of cases. I think it's pretty neat so I'm doing a Q-and-A on this.
See, if I could use eval
, I would just do this:
eval join( "\n"
, map {
my $v = $valcashe{$_};
sprintf( '$Text::Wrap::%s = %s', $_
, ( looks_like_number( $v ) ? $v : "'$v'" )
)
}
);
Text::Wrap::wrap( '', '', $text );
I even tried being tricky, but it seems that local
localizes the symbol to the virtual block, not the physical block. So this doesn't work:
ATTR_NAME: while ( @attr_names ) {
no strict 'refs';
my $attr_name = shift;
my $attr_name = shift @attr_names;
my $attr_value = $wrapped_attributes{$attr_name};
my $symb_path = "Text\::Wrap\::$attr_name";
local ${$symb_path} = $attr_value;
next ATTR_NAME if @attr_names;
Text::Wrap::wrap( '', '', $text );
}
Same physical block, and I tested the package variables before and after being set, and they even showed the proper value on their time through the loop. But testing showed that only the last variable passed through retained its value for the call to wrap
. So values only stayed localized until the end of the loop.
I think the solution is neat--even if arcane perl magick. But the end result is good because it means I can wrap legacy code that relies on package-scoped variables and be assured that the values set will be as short-lived as possible.
Axeman, you idiot! The package stash is a hash too! This works:
This does the following:
Text::Wrap
's symbol table and returns the named symbols.\( ... )
syntax passes back a reference for each item in the list.So we localize each variable for each key in
%wrapped_attributes
, and we assign it a reference for each value there.It's ugly and arcane, and it's hard to move it out of the way each time I need it--but with it, I can pre-specify and delay the localization to select places where I can put up Damien Conway's suggested barbed wire and danger signs.
If I'm going to use it, it has to be just that ugly where I use it.