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

Dear Brethren:

In several places of my module, I need to locally override several methods from another module. One way to achieve this is like this:

sub somesub { no warnings 'redefine'; local *ABC::xyz = sub {1}; # several more # .... }
However, there are several of the subroutines to override in several places of my code. I was wondering if there is a programmatic way of doing this, with a for loop, for example. However, my tests show that it's not possible, since local picks up loop's scope:
sub abc { 1 } for my $method (qw(abc)) { local *{$method} = sub { 2 }; } # Prints 1 print abc(), "\n"; if (1) { local *abc = sub { 3 }; } # Prints 1 print abc(), "\n"; eval "local \*{'abc'} = sub { 4 };"; # Prints 1 print abc(), "\n"; local *{$_} = sub { 5 } for ("abc"); # Prints 1 print abc(), "\n"; local *abc = sub { 6 } if 1; # Prints 6 print abc(), "\n";
Ideas? Thanks!

  - Dmitri.

Update 1 in response to dragonchild and Fletch:

I am writing an OO layer of APIs on top of another layer of APIs. The latter is a DB representation and includes access checking here and there buried deep in the hierarchy. I'd like to avoid using those access checks (I have my own), and so I want to replace all instances of things like

package Anypackage; sub can_read { # Some checks here }
with
sub can_read { 1 }

Replies are listed 'Best First'.
Re: Overriding several methods using 'local'
by diotalevi (Canon) on May 22, 2006 at 15:29 UTC

    Yep. True dat. I think there was a patch posted against 5.9.4 sometime in the last few months. It might have made its way back into 5.8.9.

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Overriding several methods using 'local'
by dragonchild (Archbishop) on May 22, 2006 at 15:33 UTC
    I think you might have an XY problem. I'm pretty sure that there's a better way to do what you're trying to do, but I'd need to have some more context in order to point you in the right direction.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      The post has been updated. Thanks for the input!
        In response to your update:

        This is where inheritance is quite useful.

        package My::AnyPackage; use base 'AnyPackage'; sub can_read { 1 };

        Now, whenever you would do my $obj = AnyPackage->new( ... );, instead you now do my $obj = My::AnyPackage->new( ... );. And it will "Just Work".


        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Overriding several methods using 'local'
by Fletch (Bishop) on May 22, 2006 at 15:56 UTC

    Yeah, more context is needed to be sure. But just to toss out another idea: could you perhaps convert things to method calls rather than subroutines? Then you could just change the (global) instance on which things are making calls and get the changed behavior. If you can't change things in place you might could make abc a wrapper which does the dispatch to the correct method behind the scenes.

      All of those are methods. I apologize if it wasn't clear from the original post. Update is now posted.
Re: Overriding several methods using 'local'
by educated_foo (Vicar) on May 22, 2006 at 18:19 UTC
    Does this have the desired effect?
    { package Foo; sub f { "default f\n" } sub g { "default g\n" } } sub localized(&) { local *Foo::f = sub { "localized f\n"; }; local *Foo::g = sub { "localized g\n"; }; $_[0]->(); } localized { print STDERR Foo->f, Foo->g; }
      It looks like this is exactly what I need. I will play with it and see. Thanks!