开发者

Why does modifying a Moose class in BUILD cause this error?

开发者 https://www.devze.com 2023-02-18 08:15 出处:网络
I\'m having trouble with this Moose-related error when using BUILD.When I change to BUILDALL it appears to work. Note the use of Class::MOP::load_class

I'm having trouble with this Moose-related error when using BUILD. When I change to BUILDALL it appears to work. Note the use of Class::MOP::load_class

Using BUILD

Perl version: 5.012002
Class::MOP::Version: 1.11
Moose::Version: 1.24
Applying fixup GV::WebServer::Fixups::Development
aflott-g3 at a.pl line 83.
Error: trying to call refresh() in GV::WebServer::Fixups::Development produced: The     'add_attribute' method cannot be called on an immutable instance at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 32
        Class::MOP::Class::Immutable::Trait::_immutable_cannot_call('add_attribute') called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Class/Immutable/Trait.pm line 37
        Class::MOP::Class:::around('CODE(0x13a2e028)', 'Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, ...) called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Method/Wrapped.pm line 159
        Class::MOP::Method::Wrapped::__ANON__('Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, 'default', ...) called at /opt/cidc-perl/perl-5.12.2/lib/perl5/x86_64-linux/Class/MOP/Method/Wrapped.pm line 89
        Class::MOP::Class::Immutable::Moose::Meta::Class::add_attribute('Class::MOP::Class::Immutable::Moose::Meta::Class=HASH(0x13d58...', 'architecture', 'is', 'ro', 'isa', 'Str', 'lazy', 1, '开发者_StackOverflow社区default', ...) called at a.pl line 47
        Amethyst::SystemInfo::BUILD('Amethyst::SystemInfo=HASH(0x13e83010)', 'HASH(0x13e50cc0)') called at generated method (unknown origin) line 147
        Amethyst::SystemInfo::new('Amethyst::SystemInfo') called at a.pl line 92
        GV::WebServer::Fixups::AutoSet::set() called at a.pl line 84
        GV::WebServer::Fixups::Development::refresh('GV::WebServer::Fixups::Development') called at a.pl line 114
        main::__ANON__() called at /opt/cidc-perl/perl-5.12.2/lib/perl5/Try/Tiny.pm line 76
        eval {...} called at /opt/cidc-perl/perl-5.12.2/lib/perl5/Try/Tiny.pm line 67
        Try::Tiny::try('CODE(0x13e82fe0)', 'Try::Tiny::Catch=REF(0x13e8cd50)') called at a.pl line 118

Using BUILDALL:

Perl version: 5.012002
Class::MOP::Version: 1.11
Moose::Version: 1.24
Applying fixup GV::WebServer::Fixups::Development
aflott-g3 at a.pl line 71.
aflott-g3364136 at a.pl line 81.

Full error

From this code:

package Amethyst::SystemInfo;

use v5.10;

use Moose;

use Sys::Hostname qw();
use Sys::HostIP;
use Try::Tiny;

has '_host_ip' => ('is' => 'ro', 'isa' => 'Sys::HostIP', 'default' => sub { Sys::HostIP->new });
has 'eth0_ipv4' => ('is' => 'rw', 'isa' => 'Str',);
has 'ethernet_interfaces' => ('is' => 'rw', 'isa' => 'HashRef',);
has 'hostname' => ('is' => 'ro', 'isa' => 'Str', 'default' => sub { Sys::Hostname::hostname });

sub BUILD {
    my ($self) = @_;

    $self->ethernet_interfaces($self->_host_ip->interfaces);

    if ($self->ethernet_interfaces->{'eth0'}) {
        $self->eth0_ipv4($self->ethernet_interfaces->{'eth0'});
    }

    foreach my $attrib (
        qw(architecture domain fqdn kernel kernelrelease kernelversion memorytotal operatingsystem processor processorcount swap)
      ) {
        $self->meta->add_attribute(
            $attrib => (
                'is'      => 'ro',
                'isa'     => 'Str',
                'lazy'    => 1,
                'default' => sub { return $self->_load_value($attrib) }
            )
        );
    }

    $self->meta->make_immutable;

    return;
}

sub _load_value {
    my ($self, $module_name) = @_;

    try {
        Class::MOP::load_class("Pfacter::$module_name");
    }
    catch {
        warn("Failed to load Pfacter::$module_name");
    };

    my $value = "Pfacter::$module_name"->pfact({'pfact' => {'kernel' => 'Linux'}});

    unless (defined($value)) {
        warn("finding value for $module_name returned undef");
    }

    chomp($value);

    return $value;
}

no Moose;

package GV::WebServer::Fixups::Development;

use v5.10;

sub refresh {
    warn Amethyst::SystemInfo->new->hostname;
    return GV::WebServer::Fixups::AutoSet::set();
}

package GV::WebServer::Fixups::AutoSet;

use v5.10;

sub set {
    my $sysinfo = Amethyst::SystemInfo->new;
    warn $sysinfo->hostname, ' ', $sysinfo->swap;
}

package main;

use v5.10;

use Class::MOP;
use Try::Tiny;

my $module_name = "GV::WebServer::Fixups::Development";

say('Perl version: ',        $]);
say('Class::MOP::Version: ', $Class::MOP::VERSION);
say('Moose::Version: ',      $Moose::VERSION);
say("Applying fixup $module_name");

Class::MOP::load_class($module_name);

my $ret;
try {
    $ret = $module_name->refresh;
}
catch {
    warn("Error: trying to call refresh() in $module_name produced: " . shift);
};


You are modifying the class every time you construct an object of that class. That makes no sense. Just move your class construction code out of BUILD and BUILDARGS and place it with the rest of the class construction code.

package Amethyst::SystemInfo;

use v5.10;

use Moose;

use Sys::Hostname qw();
use Sys::HostIP;
use Try::Tiny;

has '_host_ip' => ('is' => 'ro', 'isa' => 'Sys::HostIP', 'default' => sub { Sys::HostIP->new });
has 'eth0_ipv4' => ('is' => 'rw', 'isa' => 'Str',);
has 'ethernet_interfaces' => ('is' => 'rw', 'isa' => 'HashRef',);
has 'hostname' => ('is' => 'ro', 'isa' => 'Str', 'default' => sub { Sys::Hostname::hostname });

foreach my $attrib (qw(
    architecture domain fqdn kernel kernelrelease kernelversion
    memorytotal operatingsystem processor processorcount swap
)) {
    has $attrib => (
        'is'      => 'ro',
        'isa'     => 'Str',
        'lazy'    => 1,
        'default' => sub { return $_[0]->_load_value($attrib) },
    );
}

sub BUILD {
    my ($self) = @_;

    $self->ethernet_interfaces($self->_host_ip->interfaces);

    if ($self->ethernet_interfaces->{'eth0'}) {
        $self->eth0_ipv4($self->ethernet_interfaces->{'eth0'});
    }
}

sub _load_value {
    ...
}

no Moose;
__PACKAGE__->meta->make_immutable;

1;

Kudos to phaylon and bvr.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号