Changes to MooseX Modules with Moose 2.0

| No TrackBacks

We're getting closer and close to releasing Moose 2.0, and I wanted to highlight one particular change in Moose 2.0.

MooseX modules whic affect attributes, like MooseX::SemiAffordanceAccessor and MooseX::LazyRequire, now have different behavior in conjunction with roles.

When you use one of these modules in your class, it applies a trait to all of the attributes defined in your class:

package MyClass;

use Moose;
use MooseX::SemiAffordanceAccessor;

has foo => ( is => 'rw' );

In this example, the foo attribute ends up with the MooseX::SemiAffordanceAccessor::Role::Attribute trait applied to it behind the scenes. This trait is what affects how accessors are named.

With the current version of Moose, these attribute traits are also applied to attributes provided by roles:

package MyClass;

use Moose;
use MooseX::SemiAffordanceAccessor;

with 'MyRole';

has foo => ( is => 'rw' );

Any attributes provided by MyRole end up with the SemiAffordanceAccessor naming scheme.

This is a huge stinking bug. The problem is that by applying this trait, we have changed the interface provided by MyRole. One of the major uses of roles is to provide a named interface, so this is bad.

With Moose 2.0, this bug is fixed. When we apply MyRole, the attributes applied from the role no longer acquire the attribute traits of the consuming class.

However, some people might have been taking advantage of this feature, writing roles with the assumption that the consuming class uses a MooseX module.

The right thing to do is to use the relevant MooseX module in the role itself. This is not possible with Moose 1.2x, but will be possible in Moose 2.0. The only catch is that the MooseX module has to explicitly support this.

For many modules, this is trivial. Let's take MooseX::SemiAffordanceAccessor as an example. The code used to look like this:

Moose::Exporter->setup_import_methods(
    class_metaroles => {
        attribute => ['MooseX::SemiAffordanceAccessor::Role::Attribute'],
    },
);

To make it work with both new and old Moose, it becomes:

my %metaroles = (
    class_metaroles => {
        attribute => ['MooseX::SemiAffordanceAccessor::Role::Attribute'],
    },
);

$metaroles{role_metaroles} = {
    applied_attribute => ['MooseX::SemiAffordanceAccessor::Role::Attribute'],
} if $Moose::VERSION >= 1.9900;

Moose::Exporter->setup_import_methods(%metaroles);

Some MooseX modules don't have it so easy. If your MooseX applies traits to the class metaclass as well as the attributes, making it work with roles is much harder. We're planning to make this simpler in Moose 2.02, but for now your best bet is to look at a module like MooseX::Attribute::Deflator for an example of how to do this. Basically, you have to have the role "pass along" the class metaroles when the role is applied.

As a consumer of a MooseX module, updating to Moose 2.0 will be fairly simple. If you want to apply a MooseX module to attributes in role, just use the module in your roles.

We're currently working with MooseX authors to get their modules updated in preparation for the Moose 2.0 release.

We're available on irc://irc.perl.org/#moose-dev to help you update your module, or you can email us at moose@perl.org. Please contact us if you need help updating your code.

No TrackBacks

TrackBack URL: http://blog.moose.perl.org/mt-tb.cgi/169

About this Entry

This page contains a single entry by Dave Rolsky published on March 29, 2011 3:07 PM.

The Moose Ecosystem was the previous entry in this blog.

Moose 2.0 Release Candidate is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Categories

Pages

Powered by Movable Type 4.38