Overriding a require'd module's subroutine


R

Ratty

I'm using the MARC::Batch module. It refuses to process records with
character encoding issues. It dies with a warning about line 166 in
Encode.pm. I can use eval to make it skip bad records instead but I
don't want that either. I want it to do the best it can. What I need
to do is modify Encode::decode so it does not die when it can't decode
a string. This works if I add an eval to Encode.pm sitting in my perl/
lib directory. But I don't want to do it this way. I want everything
restricted to my one calling program. I seem to remember doing
something similar years ago by simply copying the subroutine, with
package name, into my program and my program would use that instead.
But it doesn't work for me this time. No errors, it simply ignores it.
Perhaps because I'm not calling the module directly this time, but
rather it is being called somewhere in the bowels of MARC::Record,
which I'm also not calling directly.

use MARC::Batch;

## Programming here

## Attempt to override
sub Encode::decode($$;$)
{
my ($name,$octets,$check) = @_;
return undef unless defined $octets;
$octets .= '' if ref $octets;
$check ||=0;
my $enc = find_encoding($name);
unless(defined $enc){
require Carp;
Carp::croak("Unknown encoding '$name'");
}
## Add eval heres
my $string;
eval { $string = $enc->decode($octets,$check); };
$_[1] = $octets if $check and !($check & LEAVE_SRC());
return $string;
}

What's the most elegant way to redefine somebody else's subroutine?
BTW, I also tried:

{
local *Encode::decode = \&myDecode;
}

Doesn't work either
 
Ad

Advertisements

R

Ratty

I'm using the MARC::Batch module. It refuses to process records with
character encoding issues. It dies with a warning about line 166 in
Encode.pm. I can use eval to make it skip bad records instead but I
don't want that either. I want it to do the best it can. What I need
to do is modify Encode::decode so it does not die when it can't decode
a string. This works if I add an eval to Encode.pm sitting in my perl/
lib directory. But I don't want to do it this way. I want everything
restricted to my one calling program. I seem to remember doing
something similar years ago by simply copying the subroutine, with
package name, into my program and my program would use that instead.
But it doesn't work for me this time. No errors, it simply ignores it.
Perhaps because I'm not calling the module directly this time, but
rather it is being called somewhere in the bowels of MARC::Record,
which I'm also not calling directly.
use MARC::Batch;
## Programming here
## Attempt to override
sub Encode::decode($$;$)
{
    my ($name,$octets,$check) = @_;
    return undef unless defined $octets;
    $octets .= '' if ref $octets;
    $check ||=0;
    my $enc = find_encoding($name);
    unless(defined $enc){
   require Carp;
   Carp::croak("Unknown encoding '$name'");
    }
    ## Add eval heres
    my $string;
    eval { $string = $enc->decode($octets,$check); };
    $_[1] = $octets if $check and !($check & LEAVE_SRC());
    return $string;
}
What's the most elegant way to redefine somebody else's subroutine?
BTW, I also tried:
{
local *Encode::decode = \&myDecode;
}
Doesn't work either

I can't see why that doesn't work, but I suggest placing your new
Encode::decode before the use statement for MARC::Batch. Perhaps
MARC::Batch stores a reference to the subroutine.

OK, got it to work - don't understand why though.

I tried just pasting the entire contents of Encode.pm on to the end
of my program and that worked. Then I started removing things until it
stopped. Found out it requires a use statement in there. As in:

package Encode;

use Encode::Alias;

sub decode($$;$)
{
my ($name,$octets,$check) = @_;
my $altstring = $octets;
return undef unless defined $octets;
$octets .= '' if ref $octets;
$check ||=0;
my $enc = find_encoding($name);
unless(defined $enc){
require Carp;
Carp::croak("Unknown encoding '$name'");
}
my $string;
eval { $string = $enc->decode($octets,$check); };
$_[1] = $octets if $check and !($check & LEAVE_SRC());
if ([email protected]) {
return $altstring;
} else {
return $string;
}
}

Doesn't work without it. I wonder why.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top