The following script p.pl
works fine:
use feature qw(say);
use strict;
use warnings;
use lib '.';
use P1;
my $obj = P1->new(name => 'John');
say "The name is: ", $obj->name;
where the class P1
is defined in file P1.pm
:
package P1;
use Moose;
has name => (is => 'rw', isa => 'Str');
1;
However, when I try to move the class P1.pm
into the main script:
#! /usr/bin/env perl
use feature qw(say);
use strict;
use warnings;
my $obj = P1->new(name => 'John');
say "The name is: ", $obj->name;
package P1;
use Moose;
has name => (is => 'rw', isa => 'Str');
I get error:
Can't locate object method "name" via package "P1" at ./p.pl line 8.
has
is just a regular function call that gets executed at runtime, so it won't get run until after your say
.
Normally you'd use
a Moose class, and use Class;
is just short for BEGIN { require Class; ... }
, so that normally, all the Moose functions like has
will have been executed during the compile time of the script that is doing the use
ing. See also "BEGIN, UNITCHECK, CHECK, INIT and END" in perlmod.
Although I don't think it's the nicest solution, you could stick your package P1;
declaration in a BEGIN { ... }
block. Or, you could put package P1
before the main code (in its own block would be best, so it has its own scope).
But there's also something to be said against putting the class in the same file in the first place, see e.g. the answers at In Perl, how do I put multiple class in a single .pm file.
You are trying to use the attribute before executing the call to has
that creates it.
A relatively simple method to inline module follows:
use feature qw(say);
use strict;
use warnings;
use FindBin qw( $RealBin );
use lib $RealBin;
BEGIN {
package P1;
use Moose;
has name => (is => 'rw', isa => 'Str');
$INC{"P1.pm"} = 1;
}
use P1;
my $obj = P1->new(name => 'John');
say "The name is: ", $obj->name;
Keep in mind it's still not quite equivalent. For example, the module is now in scope of the three pragmas in your script. Maybe you should use App::FatPacker or similar instead.