http://www.perlmonks.org?node_id=407763

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

Imagine a library of subs that are 'require'd in a bnch of files.

At the moment they are all global (ie in main::), but I want to move them to a namespace (say Util::) to avoide clashes etc.

But there's a lot of code that uses these and I don't want to have to touch every file, possibly breaking it.

So I want to define all the subs in a namespace, but for the next few months have the subs aliased to main:: as well. One at a time that's easy, but I would like to pull all the sub names from the package table and alias them all in one hit (or a loop).

I'm sure it's simple, I'm just not quite sure how to achieve it.

Update: I am thinking something like this:

sub foo::bar {print "bar\n";} %main:: = (%main::, %foo::); bar();
but that doesn't work... I'd also like to use * globs since they would be more efficient

Update 2:This works:

sub foo::bar {print "bar\n";} foreach $name (keys %foo::) { $main::{$name} = $foo::{$name}; } bar();
But i'm sure it's not efficient for a lot of symbols...

Replies are listed 'Best First'.
Re: How to alias a whole namespace to another namespace (in this case main::)
by etcshadow (Priest) on Nov 15, 2004 at 04:09 UTC
    Look into exporting. Basically, it's an easy way to tell a module, when used, to place its symbols in the namespace of the module which uses it.

    So basically, you'd convert your requires into uses, and add a few lines of code to the top of each of your "libraries" (now called "modules" by the changes you'd be making).

    I know it's not exactly what you're asking, but it's an approach that leads you down the direction you seem to be heading, so that's good. Also, it's generally the way that this sort of thing is done, these days (exporting symbols from one namespace into another).

    ------------ :Wq Not an editor command: Wq
      You are completely correct, but there is a LOT of legacy files, some of which have multi-level require's, and I'm not going to update them all at one time. It would take too much time and be too dangerous.

      This way all the developers here can gradually "modernise" code as they go without breaking older code.

        Could the original required file be changed to just have the "use module" statement. So all the files that require the old file now are "use"ing the module along with the exports.


Re: How to alias a whole namespace to another namespace (in this case main::)
by simonm (Vicar) on Nov 15, 2004 at 05:01 UTC
    This should work:
    no strict refs; *{$target_package . "::"} = *{$source_package . "::"};

    For example:

    *{"main::"} = *{"foo::"};
      sub foo::bar {print "bar\n"} *{"main::"} = *{"foo::"}; bar();

      Results in:

      Modification of a read-only value attempted at - line 2.

      And I want to add to main, not completely replace it.

        Modification of a read-only value attempted

        Sorry, I'd never tried aliasing over main that way; I guess the root package name is more special than the others.

Re: How to alias a whole namespace to another namespace (in this case main::)
by ikegami (Pope) on Nov 15, 2004 at 05:56 UTC

    This might help.

    my $src_pkg_name = 'PACKAGEA::PACKAGEB'; my $dst_pkg_name = __PACKAGE__; { no strict 'refs'; foreach (keys(%$src_pkg_name)) { my $sym_name = $_; my $src_sym_ref = "$src_pkg_name::$sym_name"; my $dst_sym_ref = "$dst_pkg_name::$sym_name"; my $ref; $ref = *$src_sym_ref{SCALAR}; *$dst_sym_ref = $ref if $ref; $ref = *$src_sym_ref{ARRAY }; *$dst_sym_ref = $ref if $ref; $ref = *$src_sym_ref{HASH }; *$dst_sym_ref = $ref if $ref; $ref = *$src_sym_ref{CODE }; *$dst_sym_ref = $ref if $ref; } }

    Update: Oops! I had forgotten to test whether this imports functions -- which would be the most important here!! -- and it doesn't. I'm not sure how to fix ,and I can't look further into it at his moment.

Re: How to alias a whole namespace to another namespace (in this case main::)
by !1 (Hermit) on Nov 15, 2004 at 16:00 UTC

    I had to do this some time back and ended up with this:

    package as; sub import { my ($class,$caller) = ($_[1],caller); die "Mal-formed package name '$class'" unless $class =~ /^(?:\w|(? +<!^)(?<!:)::(?!\z))+\z/; die "Namespace already exists" if (keys %{"$class\::"}); *{"$class\::"} = \*{"$caller\::"}; ($class .= ".pm") =~ s!::!/!g; ($caller .= ".pm") =~ s!::!/!g; $INC{$class} = exists $INC{$caller} ? $INC{$caller}:$0; 1; } 1;

    Update: Pfft, I went the wrong way. You're going to want to alias the main namespace to your target namespace as such:

    # here we are in Utils.pm package main; use as "Utils"; package Utils; ...

    The reason for this is that you cannot reassign the main:: namespace. This merely makes Utils point to main's namespace and anything declared in Utils is also being declared in main.

Re: How to alias a whole namespace to another namespace (in this case main::)
by aquarium (Curate) on Nov 15, 2004 at 12:32 UTC
    How about just setting your current namespace with "package Util", and use/require all the modules...they'll go into that namespace. When you want them in main namespace for a while, just take out "package Util" from the code.
    the hardest line to type correctly is: stty erase ^H