Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Delegating to a role in Moose

by nysus (Priest)
on Jan 12, 2018 at 08:42 UTC ( #1207142=perlquestion: print w/replies, xml ) Need Help??
nysus has asked for the wisdom of the Perl Monks concerning the following question:

I have this code, which works, that allows me to access some custom methods in a role I created. For example:

{ package Server; use Carp; use Moose; use Net::OpenSSH; use Config::Simple; with 'MyOpenSSH'; has 'ssh' => (is => 'ro', isa => 'Net::OpenSSH', required => 1, hand +les => qr/.*/, ); } { package MyOpenSSH; use Moose::Role; sub grab { my $self = shift; $self->_check_command(@_); my $result = $self->ssh->capture(@_); return $result if ($? == 0 && !$self->ssh->error); } } use Server; my $server = Server->new(ssh => Net::OpenSSH->new('me@')); print $server->grab('ls');

I'm trying to get the above to work following the documentation for Moose delegation which states the following:

You can use a role name as the value of handles: has 'uri' => ( is => 'ro', isa => 'URI', handles => 'HasURI', ); Moose will introspect the role to determine what methods it provides a +nd create a name-for-name mapping for each of those methods.

So I tried modifying the attribute line in the Server code like so:

has 'ssh' => (is => 'ro', isa => 'Net::OpenSSH', required => 1, hand +les => 'MyOpenSSH', );

However, this just results in an error:

You cannot overwrite a locally defined method (grab) with a delegation

Other attempts to get this working resulted in failure as well. What am I missing?

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
$nysus = $PM . ' ' . $MCF;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Delegating to a role in Moose
by Arunbear (Prior) on Jan 12, 2018 at 11:50 UTC
    Hi nysus, the intention of
    handles => 'Some::Role',
    is that Some::Role simply acts as an interface i.e. it describes required methods but does not implement them.

    There is an example of this in the Moose test suite:

    { package Foo::Bar; use Moose::Role; requires 'foo'; requires 'bar'; package Foo::Baz; use Moose; sub foo { 'Foo::Baz::FOO' } sub bar { 'Foo::Baz::BAR' } sub baz { 'Foo::Baz::BAZ' } package Foo::Thing; use Moose; has 'thing' => ( is => 'rw', isa => 'Foo::Baz', handles => 'Foo::Bar', ); package Foo::OtherThing; use Moose; use Moose::Util::TypeConstraints; has 'other_thing' => ( is => 'rw', isa => 'Foo::Baz', handles => Moose::Util::TypeConstraints::find_type_constraint( +'Foo::Bar'), ); }
    Here you can see that the Foo::Bar role is used to specify delegation, but the actual methods are implemented in Foo::Baz.

      Thanks, but I'm not sure I follow. The documentation doesn't mention using Moose::Util::TypeConstraints. What, exactly, does the code in the documentation do?</code>

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
      $nysus = $PM . ' ' . $MCF;
      Click here if you love Perl Monks

        Moose::Util::TypeConstraints isn't really important here and I should have edited it out of the snippet. The important thing to understand is
        package Foo::Bar; use Moose::Role; requires 'foo'; requires 'bar';
        i.e. required methods. This is how a role indicates that a class consuming it should have some extra behaviour that the role depends on. Taking this to an extreme you can even have a role that only has required method specifiers - this gives you something similar to the interface construct found in Java/C#/PHP.

        And this latter type of role is what is intended to be used when you specify a role to the 'handles' clause.

        Does that make sense?
Re: Delegating to a role in Moose
by Dallaylaen (Hermit) on Jan 12, 2018 at 10:46 UTC

    Hello nysus,

    It looks like you can't have with "Foo"; in your class and handles "Foo"; in an attribute at the same time, which is quite natural - you either impersonate a role, or point to someone else performing it for you. You have to choose.

    I'm new to Moose, though. Take my advice with a grain of salt.

    Hope that helps.

    UPD: a minimal example

    ==> <== #!/usr/bin/env perl use strict; use warnings; use Foo; print Foo->new->bar, "\n"; ==> <== package Foo; use Moose; with "Roo"; use Goo; has goo => is => "rw", isa => "Roo", handles => "Roo" , default => sub { Goo->new; }; 1; ==> <== package Goo; use Moose; with "Roo"; 1; ==> <== package Roo; use Moose::Role; sub bar { 42 }; 1;

    This doesn't work. One needs to comment out either "with", or "handles" in for the perl -I. to output 42 correctly.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1207142]
Approved by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2018-06-19 23:11 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (116 votes). Check out past polls.