Reputation: 354
I'm trying to create a child class of a custom module that we have in our code base. We have our modules in a directory that we include in all of our files. So we begin with
use Env;
use lib "$ENV{OurKey}/RootLib"; # All of our modules are here
Next, I have my parent module, located in RootLib/Dir1/Parent.pm
whose code has been long standing, and so I'd rather not change any of it, but rather have the child be able to inherit from it as it is.
package Parent;
use strict;
use warnings;
use Env;
use lib "$ENV{OurKey}/RootLib";
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = {};
# Some other stuff
bless ($self, $class);
return $self;
}
At this point, I'm a bit lost, because I've seen a number of different ways to define the child constructor, but none have worked for me. This is what I have, but it does not work because subroutines that should be inheritied from the parent cannot be found in the child package. The child package is in RootLib/Dir1/Dir2/Child.pm
package Child;
use strict;
use warnings;
use vars qw(@ISA);
use Env;
use lib "$ENV{OurKey}/RootLib";
require Dir1::Parent;
push @ISA, 'Dir1::Parent';
sub new {
# This constructor is clearly incorrect, please help
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = Parent::new($class);
bless ($self, $class);
return $self;
}
And then, in my test.pl file, I have
use Env;
use lib "$ENV{OurKey}/RootLib";
use Dir1::Dir2::Child;
my $childObj = Child->new();
$childObj->inheritedParentSubroutine( ... ); # Cannot find this subroutine
Upvotes: 2
Views: 203
Reputation: 385645
The to-be parent class has package Parent;
, but then you have @ISA = 'Dir1::Parent';
. Those don't match, which is why the method can't be found. (That, and the fact that you didn't actually define the method anywhere!)
The file name, the name in the package
statement, the name in the use
statement, and the name in @ISA
must all match.
What follows are two possible solutions.
Dir1::Parent
and Dir1::Dir2::Child
use lib "$ENV{OurKey}/RootLib";
use Dir1::Parent qw( );
use Dir1::Dir2::Child qw( );
(Note that use Env
was removed since it wasn't being used.)
(.../RootLib/)Dir1/Parent.pm
:
package Dir1::Parent; # Must match the file name.
use strict;
use warnings;
...
(.../RootLib/)Dir1/Dir2/Child.pm
:
package Dir1::Dir2::Child; # Must match the file name.
use strict;
use warnings;
use Dir1::Parent qw( ); # Must match the file name
our @ISA = 'Dir1::Parent'; # and the package name.
-or-
use parent 'Dir1::Parent'; # This can replace the other two lines.
...
Parent
and Child
Don't modify @INC (e.g. via use lib
) in modules. Your script should contain the following:
use lib
"$ENV{OurKey}/RootLib/Dir1",
"$ENV{OurKey}/RootLib/Dir1/Dir2";
use Parent qw( );
use Child qw( );
(Note that it's really weird to have a library directory inside of another library directory!)
(.../RootLib/Dir1/)Parent.pm
:
package Parent; # Must match the file name.
use strict;
use warnings;
...
(.../RootLib/Dir1/Dir2/)Child.pm
:
package Child; # Must match the file name.
use strict;
use warnings;
use Parent qw( ); # Must match the file name
our @ISA = 'Parent'; # and the package name.
-or-
use parent 'Parent'; # This can replace the other two lines.
...
As for the constructors,
Parent:
sub new {
my $class = shift; # That proto thing is a bad practice.
my $self = bless({}, $class); # Don't need two lines to do this.
# ...
return $self;
}
Child:
sub new {
my $class = shift; # That proto thing is a bad practice.
my $self = $class::SUPER->new(); # Don't need two lines to do this.
# If you don't need to do anything here,
# ... # you can just inherit the parent's new
# by removing this sub entirely.
return $self;
}
Upvotes: 0
Reputation: 118595
The parent class declares it is in package Parent
(even if the file that contains it is Dir1/Parent.pm
), so the child's @ISA
should just include Parent
.
Or you can work around your unfortunate directory structure with some additional use lib ...
statements.
package Child;
use lib "$ENV{OurKey}/RootLib/Dir1";
require Parent; # found in $OurKey/RootLib/Dir1/Parent.pm
our @ISA = ('Parent');
...
# test.pl
use lib "$ENV{OurKey}/RootLib/Dir1/Dir2";
use Child; # found in $OurKey/RootLib/Dir1/Dir2/Child.pm
...
Upvotes: 2