开发者

Moose - imported functions don't count as role methods?

开发者 https://www.devze.com 2023-04-04 00:18 出处:网络
I have a role that declares that it requires a method (with requires). I\'m trying to install the method by directly defining it in the class\'s symbol ta开发者_开发技巧ble.

I have a role that declares that it requires a method (with requires). I'm trying to install the method by directly defining it in the class's symbol ta开发者_开发技巧ble. However, in some cases it works and in others it doesn't.

In the following, WORKS means no errors are reported, DOESN'T WORK means I get the error: 'arole' requires the method 'finddepth' to be implemented by 'aclass'

package arole;

use Moose::Role;

requires 'finddepth';

package anexporter;

sub import {
  no strict 'refs';
  *{ "aclass::finddepth" } = sub {};
}

package anexporter2;
sub import {
  eval "sub aclass::finddepth {}";
}

package aclass;

use Moose;

# WORKS:
# sub finddepth { }

# WORKS:
# BEGIN { *{finddepth} = sub {} };

# DOESN'T WORK:
# use File::Find qw(finddepth);

# DOESN'T WORK:
# BEGIN { anexporter->import };

# WORKS:
# BEGIN { no strict 'refs'; *{ "aclass::finddepth" } = sub { }};

# WORKS:
# BEGIN { anexporter2->import };

with 'arole';

1;


The problem here is that Moose tries very hard to track where methods are coming from so that anything not defined in the local package isn't accidentally treated as a method.

If instead of using the raw glob you were to use the Moose metaprotocol to inject the import this would work, because Moose would then know you were trying to explicitly add a method.

package anexporter {

    sub import {
        aclass->meta->add_method(finddepth => sub {})
    }

}

However this does mean that anything on CPAN (like File::Find's finddepth) would need to be wrapped. Which since typically exports aren't expecting to be called as methods, would probably need to happen anyway.


Your role is looking for a method named finddepth; simply importing it from some other package does not a method make. I'd wrap it in a method, as your role methods would need to call finddepth as a method anyways, to have everything resolve properly.

# in package aclass
use File::Find;

sub finddepth { shift; File::Find::finddepth(@_) }

This has a couple advbantages: it's not surprising, it's not magical, and everything works as expected.

0

精彩评论

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