Include / eval perl file in a unique namespace defined at runtime

I am writing a tool that should import several other perl configuration files. Files are not wrapped w / packages and may have similar or conflicting variables / functions. I have no way to change the format of these files, so I have to work on what they are. What I was going to do was import each into a unique namespace, but I did not find a way to do this with do, requireor use. If I do not use dynamic names, just a solid name, I can do it.

Want something like this:

sub sourceTheFile {
  my ($namespace, $file) = @_;
  package $namespace;
  do $file;
  1;
  return;
}

This does not work because the package command requires a constant for the name. So, I am trying something like this:

sub sourceTheFile {
  my ($namespace, $file) = @_;
  eval "package $namespace;do $file;1;"
  return;
}

, do, main:: , . , do. ( , cat $file eval.)

Devel::Symdump, , .

:

my $xyz = "some var";
%all_have_this = ( common=>"stuff" );

, temp , , . , , ? Perl, , .

+4
2

, eval . , ? , . :

use strict;
use warnings;

use Devel::Symdump;
use File::Temp;

my $file = './test.pl';
my $namespace = 'TEST';
{
    my $fh = File::Temp->new();
    print $fh "package $namespace;\n";
    print $fh "do '$file';\n";
    print $fh "1;\n";
    close $fh;
    do $fh->filename;
}
+3

Perl use require , @INC. , :

package MyIncHook;

use strict;
use warnings;

use autouse Carp => qw( croak );

use File::Spec::Functions qw( catfile );

sub import {
    my ($class, $prefix, $location) = @_;
    unshift @INC, _loader_for($prefix, $location);
    return;
}

sub _loader_for {
    my $prefix = shift;
    my $location = shift;

    $prefix =~ s{::}{/}g;

    return sub {
        my $self = shift;
        my $wanted = shift;

        return unless $wanted =~ /^\Q$prefix/;

        my $path = catfile($location, $wanted);
        my ($is_done);

        open my $fh, '<', $path
            or croak "Failed to open '$path' for reading: $!";

        my $loader = sub {
            if ($is_done) {
                close $fh
                    or croak "Failed to close '$path': $!";
                return 0;
            }
            if (defined (my $line = <$fh>)) {
                $_ = $line;
                return 1;
            }
            else {
                $_ = "1\n";
                $is_done = 1;
                return 1;
            }
        };

        (my $package = $wanted) =~ s{/}{::}g;
        $package =~ s/[.]pm\z//;

        my @ret = (\"package $package;", $loader);
        return @ret;
    }
}

__PACKAGE__;
__END__

, $path .

:

#!/usr/bin/env perl

use strict;
use warnings;

use MyIncHook ('My::Namespace', "$ENV{TEMP}/1");

use My::Namespace::Rand;

print $My::Namespace::Rand::settings{WARNING_LEVEL}, "\n";

$ENV{TEMP}/1/My/Namespace/Rand.pm :

%settings = (
    WARNING_LEVEL => 'critical',
);

:

C:\Temp> perl t.pl
critical

, , .

+3

Source: https://habr.com/ru/post/1684415/


All Articles