tags:

views:

150

answers:

3

I need to define some modules and use them all in the same file. No, I can't change the requirement.

I would like to do something like the following:

{
    package FooObj;

    sub new { ... }

    sub add_data { ... }
}

{
    package BarObj;

    use FooObj;

    sub new { 
        ... 
        # BarObj "has a" FooObj
        my $self = ( myFoo => FooObj->new() );
        ...
    }

    sub some_method { ... }
}

my $bar = BarObj->new();

However, this results in the message:

Can't locate FooObj.pm in @INC ...
BEGIN failed...

How do I get this to work?

+9  A: 

Drop the use. Seriously.

use tells perl to read in the code from another file, which you don't need to do because the code is in the same file.

For more details, see my Perl Iron Man blog post on "Files and Packages in Perl".

Dave Sherohman
+6  A: 

You only need to use use to load a file. It's really only incidently that its argument looks like a module name.

If you need to interact with a package (and that's all it is: not a module or an object), you just need to have it defined before you want to use it.

brian d foy
+2  A: 

By convention we put one package in one file and name them the same thing, but that is just for convenience. You can put multiple packages in a single file. Since they are already loaded, you do not need to use 'use'. You also do not need to create special scoping for the packages, as the package keyword takes care of that. So you don't need those brace blocks.

use uses a package naming convention to find the appropriate file to load. The package keyword inside the module defines the namespace. And the import functions handle the package loading (generally inherited from Exporter).

#!/usr/bin/perl

use strict;
use warnings;

package FooObj;

sub new
{
        my $this  = shift;
        my $class = ref($this) || $this;
        my $self  = {};
        bless $self, $class;
        $self->initialize();
        return $self;
}

sub initialize { }
sub add_data   { }

package BarObj;

#use FooObj; <-- not needed.

sub new
{
        my $this  = shift;
        my $class = ref($this) || $this;
        my $self  = { myFoo => FooObj->new() };
        bless $self, $class;
        $self->initialize();
        return $self;
}
sub initialize  { }
sub some_method { }
sub myFoo       { return $_[0]->{myFoo} }

package main;
use Test::More;
my $bar = BarObj->new();
isa_ok( $bar,        'BarObj', "bar is a BarObj" );
isa_ok( $bar->myFoo, 'FooObj', "bar->myFoo is a FooObj" );
done_testing();

__DATA__

ok 1 - bar is a BarObj isa BarObj
ok 2 - bar->myFoo is a FooObj isa FooObj
1..2
spazm
+1 For interesting info, however I still prefer using the braces as I think it adds visual clarity.
Robert S. Barnes
Robert, I see your point. I often use (named) bare braces for visual clarity -- usually just before I decide that a given section needs to be refactored into its own routine or that a driver script needs to move more functionality back to the module.I don't often put multiple packages in a single file, so haven't really considered the need to brace or not to brace.
spazm
It's not only clarity, but it's a scoping issue. Packages do not create a scope, so that my() variable you have there is file scoped without the braces that would limit it otherwise.
brian d foy
`our` variables will also become file scoped without braces around the package. `package A; our $DEBUG = 'A'; package B; print $DEBUG;` prints 'A'
Eric Strom