How to we dynamically create missing attributes in Moo or Moose?

496 views Asked by At

We have a sample code like below. Is it possible to to capture all missing attributes invoked in package FooBar and create it dynamically? This is something like PHP's __call.

test.pl

package Person;
use feature qw(say);
use Moo;

has name => (is => "ro");

my $p = Person->new(name => "John");

say $p->name;

# The missing attribute method will be dynamically created when 
# invoked even it's not declared in Person.
say $p->lalala;

$ perl test.pl
John
Can't locate object method "lalala" via package "Test" at test.pl line 13.
1

There are 1 answers

6
choroba On

It's possible using AUTOLOAD and metaprogramming, the question remains Why.

There might be nicer ways using parameterized roles, but I just wanted to quickly show how to do it. I would reject such code in a review (I'd expect at least a comment explaining why autoloading is needed).

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

{   package MyObj;
    use Moose;

    sub AUTOLOAD {
        my ($self) = @_;
        ( my $method = our $AUTOLOAD ) =~ s/.*:://;
        (ref $self)->meta->add_attribute($method, is => 'rw');
        goto &$method
    }
}

say 'MyObj'->can('lalala');  # No, it can't.

my $o = 'MyObj'->new;
$o->lalala(12);              # Attribute created.
say $o->lalala;              # 12.

Update: Previously, my code was more complex, as it replied to @simbabque's comment to the question: it showed how to add the attribute to an instance, not the whole class.