Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Dynamically Changing Your Namespace

by Ovid (Cardinal)
on Mar 30, 2007 at 08:34 UTC ( [id://607416]=perlquestion: print w/replies, xml ) Need Help??

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

Sometimes (not often), I find that I want to change my namespace dynamically. Typically this is done in a string eval and all code in that namespace needs to be in that string. What I'd like to do is something like this:

{ switch_to_namespace($namespace); $some_class->require; $some_class->import(@list); }

I can just wrap that in an eval, but that loses my compile-time syntax checking. I'd prefer to avoid that.

I assume that this is actually compile time behavior which can't be overridden, but I've been wrong before and I'd be happy to be wrong now.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Dynamically Changing Your Namespace
by Anno (Deacon) on Mar 30, 2007 at 11:22 UTC
    The package code is compiled into is what "scalar caller(0)" would return if it were called. It is determined at compile time, there is nothing you can do at run time to change it.

    Anno

      No, code isn't immutable. It's just difficult to change. All you'd have to do is find the pointers off all the COP nodes in the optree and change them to point somewhere else.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        Ah, so that's what the COP nodes are.

        While true, what you are saying rather stresses my meaning than contradict it. Changing pointers in the op tree isn't something you do in routine Perl programming.

        Anno

        ... and change the bindings of all CVs compiled within that scope, if it's important.

Re: Dynamically Changing Your Namespace
by TOD (Friar) on Mar 30, 2007 at 11:54 UTC
    i think the point you're aiming at lies in how you use the eval() function. the perl docs imprecise about the possibilites this mighty function implies. if you take a look at how the ModPerl::RegistryCooker handles compilation, caheing and execution of CGI-like scripts within their individual namespaces, you might find an answer to your question.
    the perldoc says about eval():
    eval EXPR
    eval BLOCK
    eval In the first form, the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar con- text) is first parsed, and if there weren't any errors, executed in the lexical context of the current Perl program, so that any variable settings or subroutine and format defini- tions remain afterwards. Note that the value is parsed every time the "eval" executes. If EXPR is omitted, evaluates $_. This form is typically used to delay parsing and subse- quent execution of the text of EXPR until run time.

    In the second form, the code within the BLOCK is parsed only once--at the same time the code surrounding the "eval" itself was parsed--and executed within the context of the cur- rent Perl program. This form is typically used to trap exceptions more efficiently than the first (see below), while also providing the benefit of checking the code within BLOCK at compile time.

    to be more precise, an example:
    suppose there is a file named
    my $filename = '/var/lib/some_dir/sume_subdir/filename';

    which contains the code we want to be executed within its own, individual namespace. the first step is to construct the namespace:
    my $nspace = $filename; $nspace =~ s/[^a-zA-Z]/_/g;

    now $nspace will be '_var_lib_some_dir_some_subdir_filename'
    in order to be perl-compliant, prepend this name with something like
    $nspace= "ROOT::NameSpace::$nspace";

    now slurp in the contents of $filename:
    open FILE, $filename or die $!; my @content = <FILE>; close FILE;

    i assume the code in $filename is executable, and what we want is to prevent perl from executing it, except it does so within the namespace we want it to do. hence we make a module out of our code:
    my $eval = qq~package $nspace; sub handler { local $0 = $filename;~ . join('', @content);

    what we now have in our hands, is a full-fledged perl module, which won't be executed, but just compiled when we now call
    eval $eval; die $@ if $@; # will die if there are any compile time errors.

    now $eval contains the compiled code from the freshly created module. later on you execute this code by simply calling its handler() method:
    my $codevector_name = join '::', $nspace, 'handler'; my $codevector = &\{ $codevector_name }; eval { $codevector->(@_) }; # pass arguments to the handler die $@ if $@

    this is how ModPerl has been knitted, and most of what i've been telling stems from a code which i derived from ModPerl::RegistryCooker for my own project. three hurrah to Andreas J. Koenig, Doug MacEachern and Stas Bekman, who do a wonderful job.
Re: Dynamically Changing Your Namespace
by Moron (Curate) on Mar 30, 2007 at 13:35 UTC
      Argh... another two CPAN one-liner modules:
      # alias *{$new_package . '::'} = *{$old_package . '::'}; # remove undef *{$new_package . '::'};
        Is there something virtuous about using a lot of code to do something?

        -M

        Free your mind

Re: Dynamically Changing Your Namespace
by educated_foo (Vicar) on Mar 30, 2007 at 14:17 UTC
    I can just wrap that in an eval, but that loses my compile-time syntax checking.
    If you typically do this in a string eval, I'm not sure what it buys you to avoid eval. I guess you could wrap the whole thing up in a BEGIN if you want to see errors as soon as possible, though.
Re: Dynamically Changing Your Namespace
by phaylon (Curate) on Mar 31, 2007 at 16:35 UTC

    This could work easily if there were a non-scoping (read: unhygienic) version of eval. Then it would be just a

    if ($foo) { unhygienic_eval "package $foo"; sub bar { 23 } }

    But I have no experience with the perl guts and expect this to be much more work than it looks like.


    Ordinary morality is for ordinary people. -- Aleister Crowley

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://607416]
Approved by pKai
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-25 17:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found