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' );



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to