Search code examples
perldelegatesmousemoose

How can I delegate to the first element of an array with Mouse?


I have an object which holds a stack of objects. The object represents the current state, and each object in the stack holds the state at a particular level of nesting.

package State;

use Mouse;
use RealState;

has state_stack => {
    is    => 'rw',
    isa   => 'ArrayRef[RealState]',
    default => sub {
        return [RealState->new]
    }
};

I want State to delegate to State->state_stack->[0]. How can I do that efficiently with Mouse (so no meta hacking). I cannot use Moose, my project cannot have any dependencies (I'm bundling Mouse::Tiny).

"You can't" is fine, I'll write an AUTOLOAD.


Solution

  • You can't it directly, but there's a hack better than AUTOLOAD. That is, RealState->meta->get_all_method_names() gives you method names which are defined in RealState.

    #!perl
    use 5.14.0;
    package RealState {
        use Mouse;
    
        sub foo { 'foo' }
        __PACKAGE__->meta->make_immutable;
    }
    package State {
        use Mouse;
    
        has stack => (
            is => 'rw',
            isa => 'ArrayRef',
            default => sub { [ RealState->new ] },
        );
    
        # define delegates for stack->[0]
        my $meta = __PACKAGE__->meta;
        foreach my $name(RealState->meta->get_all_method_names) {
            next if Mouse::Object->can($name); # avoid 'new', 'DESTROY', etc.
    
            # say "delegate $name";
            $meta->add_method($name => sub {
                my $self = shift;
                $self->stack->[0]->$name(@_);
            });
        }
    
        $meta->make_immutable;
    }
    
    my $state = State->new();
    say $state->foo();