a7omiton
a7omiton

Reputation: 1617

How to initialize classes in constructor using Moose

The way I'm doing it is:

package 'My::FH';
use Moose;

has 'csv' => (
 is => 'ro',
 isa => 'Text::CSV',
);

sub store_data {
    my $self = shift;
    ... read lines...
    $self->csv->parse($line);
}

__PACKAGE__->meta->make_immutable;
1;

but when calling $self->csv->parse in the subroutine I get the following error:

cant call method 'parse' on an undefined value

It's not entirely clear to me how OOP works with Moose; is has a replacement for use? If so, I'm not sure why the module specified isn't instantiated (or maybe it is??).

Upvotes: 0

Views: 338

Answers (1)

stevenl
stevenl

Reputation: 6798

has is not a replacement for use; it is completely different. has declares an attribute in your class.

Your declaration:

has 'csv' => (
  is => 'ro',
  isa => 'Text::CSV',
);

simply declares an attribute called csv that is readonly ro and is of the type Text::CSV. But the type declaration does not import the module for you. You will need to use Text::CSV separately.

An object instance of My::FH will also need a reference to an instance of Text::CSV. Somewhere in your code you need to instantiate Text::CSV and assign it to your csv attribute. Moose does not initialise the attribute automatically for you (unless you include some extra options in your attribute declaration). You could do it using the default or builder (with lazy) options:

has csv => (
  is      => 'ro',
  isa     => 'Text::CSV',
  default => sub { Text::CSV->new( { your => 'options' } ) },
);

Alternatively, you could pass it to the constructor (though I'm guessing this is not what you're looking for):

my $fh = My::FH->new( csv => Text::CSV->new );

Have a read of this section of the Moose manual: https://metacpan.org/pod/Moose::Manual::Attributes.

Upvotes: 1

Related Questions