I'm trying to write a perl module using Mouse, and after the object has been initialized, but before the user makes any calls, I need to initialize object1 with the two values from object2 and object3 that the user was required to give. I tried to use Mouse's after
feature to have a subroutine called after new
:
package Test;
use strict;
use Mouse;
has 'object1' => ( is => 'rw', isa => 'Any');
has 'object2' => ( is => 'ro', isa => 'Str', required => 1);
has 'object3' => ( is => 'ro', isa => 'Str', required => 1);
after 'new' => sub {
my ($self) = @_;
$self->object1(#do stuff with object2 and object3);
};
1;
However, currently I get this error:
Invalid object instance: 'Test' at lib/Test.pm line 18.
Is there a way I can initialize a value with user supplied values before the user gets the object reference returned to them?
Mouse is compatible with Moose. Object creation has the following phases:
BUILDARGS
method if one is defined. This can munge the arguments before Moose/Mouse touch them, e.g. to provide default arguments or to accommodate other calling styles than the keyword convention.has
) are populated.BUILD
method. This is the point where you can also perform remaining initialization that can't be expressed with has
declarations.So your example might become:
use strict;
use warnings;
package Your::Class;
use Mouse;
has 'object1' => ( is => 'rw', isa => 'Any');
has 'object2' => ( is => 'ro', isa => 'Str', required => 1);
has 'object3' => ( is => 'ro', isa => 'Str', required => 1);
sub BUILD {
my ($self) = @_;
$self->object1($self->object2 . $self->object3);
};
package main;
use Test::More;
# Your::Class->new(object2 => "foo", object3 => "bar");
my $instance = new_ok('Your::Class', [object2 => "foo", object3 => "bar"]);
is($instance->object1, "foobar");
done_testing;
To learn more about object construction in Moose and Moose-compatible object systems, read Moose::Manual::Construction
.