On Thursday 06 May 2004 04:41 am, Wiggins d Anconia wrote:
[snip]
> Generally when I hit an unrecognized warning it is time to check the
> perldiag docs,
>
> perldoc perldiag
>
> Conveniently,
>
> "Variable "%s" will not stay shared
> (W closure) An inner (nested) named subroutine is referencing a lexical
> variable defined in an outer subroutine.
>
> When the inner subroutine is called, it will probably see the value of
> the outer subroutine's variable as it was before and during the *first*
> call to the outer subroutine; in this case, after the first call to the
> outer subroutine is complete, the inner and outer subroutines will no
> longer share a common value for the variable. In other words, the
> variable will no longer be shared.
>
> Furthermore, if the outer subroutine is anonymous and references a
> lexical variable outside itself, then the outer and inner subrou
> tines will never share the given variable. This problem can usually
> be solved by making the inner subroutine anonymous, using the "sub {}"
> syntax. When inner anonymous subs that reference variables in outer
> subroutines are called or referenced, they are automatically rebound to
> the current values of such variables."
>
Thank you Wiggins,
But maybe I could explain the overall picture. I am trying to embed
'any' script (whthout modification) in perl; I use a perl package
(which is run via a c program) to maintain 'persistence' of the script
which is read from disk. This must be done in the mod_perl registry
for cgi scripts, but my search of the mod_perl source so far has
been fruitless.
Suppose this script (ev1.pl) is read from disk:
#!/usr/bin/perl
use strict;
use warnings;
my $arg1 = shift @ARGV;
my $arg2 = shift @ARGV;
show_stuff();
sub show_stuff
{
print "$arg1 and $arg2\n";
}
Standalone, this runs fine. Now my perl package (listed at the end),
maintains a cache of scripts that have been read from disk, If a
script has not yet been seen (tne generated package name for the
script is not in the cache), a package name is generated from
the script file name and it makes a package of it as follows:
package Embed::ev1_2epl; sub __handler__ { shift; @ARGV = @_; my $code = sub
{ #!/usr/bin/perl
use strict;
use warnings;
my $arg1 = shift @ARGV;
my $arg2 = shift @ARGV;
show_stuff();
sub show_stuff
{
print "$arg1 and $arg2\n";
}
}; &$code; }
An 'eval' of the above statement is done to 'compile' it and the
package name is saved a cache.
Next the script is 'run' using the package name generated (either
a package just compiled or from the cache):
eval {$package->__handler__(@user_args);};
is done. Same problem (of course - because as you pointed out
it has a nested subroutine issue) :
$ perl t1.pl
ev1.pl is package Embed::ev1_2epl
Variable "$arg1" will not stay shared at (eval 1) line 13.
Variable "$arg2" will not stay shared at (eval 1) line 13.
jack and jill
already compiled Embed::ev1_2epl
jack and jill
Sorry all, I know this is a bit much...
Aloha => Beau;
'persistent' perl package (Embed::Persistent) and test code follows.
It is a knock-off of the sample in the perlembed man page.
t1.pl:
#!/usr/bin/perl
package Embed::Persistent;
use strict;
use warnings;
our %Cache;
sub valid_package_name {
my($string) = @_;
$string =~ s/([^A-Za-z0-9\/])/sprintf("_%x",unpack("C",$1))/eg;
$string =~ s|/(\d)|sprintf("/_%x",unpack("C",$1))|eg;
$string =~ s|/|::|g;
$string = "::$string" unless $string =~ /^::/;
return "Embed" . $string;
}
sub _eval_file {
my ($filename, @user_args) = @_;
my $package = valid_package_name ($filename);
my $mtime = -M $filename;
if(defined $Cache{$package}{mtime}
&&
$Cache{$package}{mtime} <= $mtime)
{
print "already compiled $package\n";
} else {
local *FH;
open FH, $filename || die;
my $sub = do { local $/; <FH>; };
close FH;
my @chunks = split "(\n__END__)", $sub;
$sub = shift @chunks;
my $end = join( "", @chunks ) || '';
my $eval = "package $package; sub __handler__ { shift; [EMAIL PROTECTED] =
[EMAIL PROTECTED];
my \$code = sub { $sub \n}; &\$code; } \n$end";
print $eval;
print "$filename is package $package\n";
my $cmpl_error = do {
my($filename,$mtime,$package,$sub);
@_ = @user_args;
eval $eval;
$@;
};
die "perl compile error in $filename: $cmpl_error\n"
if $cmpl_error;
$Cache{$package}{mtime} = $mtime;
}
my $eval_error = $@ = do {
eval {$package->__handler__(@user_args);};
$@;
};
die "perl run-time error in $filename: $eval_error\n"
if $eval_error;
}
1;
Embed::Persistent::_eval_file( 'ev1.pl', 'jack', 'jill' );
Embed::Persistent::_eval_file( 'ev1.pl', 'william', 'mary' );
--
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html