Moose::...Overview(3)
π NAME π
Moose::Cookbook::Extending::ExtensionOverview β the Moose extension overview, bestie. That's the whole vibe. It's a Perl thing, it lives in the User Contributed Perl Documentation, and it's here to hold your hand through every single way you can extend Moose. π¦
β¨ VERSION β¨
version 2.4000 πΈ
π DESCRIPTION π
okay so. Moose gives you several different ways to hook in and change how it behaves β and bestie, there is a LOT of behavior in there waiting to be changed. This recipe is the lil overview tour of every extension method, plus some recommendations on which tool to reach for. π
but fr fr, if you haven't read the recipes on metaclasses yet, go read those first. You literally cannot write Moose extensions without understanding metaclasses, and those recipes also show off some basic extension mechanisms, like metaclass subclasses and traits. no skipping, iykyk. π
π«Ά Playing Nice With Others π«Ά
One of the goals of this whole overview is to help you build extensions that cooperate well with other extensions. And that matters so much more if you're planning to release your extension to CPAN. π
Moose ships with several modules that exist specifically to help you write cooperative extensions:
Moose::ExporterMoose::Util::MetaRole
By using these two, you make sure your extension plays nice with both the Moose core features and any other CPAN extension using those same modules. it's giving community, it's giving teamwork. π
π PARTS OF Moose YOU CAN EXTEND π
The kinds of things you might wanna do in Moose extensions fall into a few broad categories. Let's go. π₯
π Metaclass Extensions π
One way to extend Moose is by extending one or more Moose metaclasses. For example, in Moose::Cookbook::Meta::Table_MetaclassTrait we saw a metaclass role that added a "table" attribute to the metaclass. If you were writing an ORM, that would be a totally logical extension to make. π
A lot of the Moose extensions on CPAN work by providing an attribute metaclass role. Example: the MooseX::Aliases module provides an attribute metaclass trait that lets you specify aliases to install for methods and attribute accessors. iconic behavior honestly.
A metaclass extension can be packaged as a role/trait or a subclass. And if you can β we recommend using traits instead of subclasses, because it is sooooo much easier to combine disparate traits than it is to combine a whole bunch of subclasses. combining subclasses is lowkey a nightmare. π
When your extensions are implemented as roles, you can apply them with the Moose::Util::MetaRole module. easy. β¨
π Providing Sugar Functions π
As part of a metaclass extension, you might also want to provide some sugar functions, exactly like Moose.pm does. Moose provides a helper module called Moose::Exporter that makes this much simpler. We will be using Moose::Exporter in several of the extension recipes. get excited. π
π¦ Object Class Extensions π¦
Another super common Moose extension technique is changing the default object class's behavior. Same deal as metaclass extensions: this can be done with a role/trait or with a subclass. For example, the MooseX::StrictConstructor extension applies a trait that makes the constructor reject arguments which don't match its attributes. strict queen. π
Object class extensions often include metaclass extensions too. In particular, if you want your object extension to work when a class is made immutable, you may need to modify the behavior of some or all of these objects:
Moose::Meta::InstanceMoose::Meta::Method::ConstructorMoose::Meta::Method::Destructor
And good news: the Moose::Util::MetaRole module lets you apply roles to the base object class, as well as to the meta classes just mentioned. π«Ά
πΈ Providing a Role πΈ
Some extensions come in the form of a role for you to consume. The MooseX::Object::Pluggable extension is a great example of this. And here's the plot twist β despite the "MooseX" name, it does not actually change anything about Moose's behavior. Nope! It's just a role that an object which wants to be pluggable can consume. π
If you're implementing this sort of extension, you don't need to do anything special. You simply create a role and document that it should be used via the normal "with" sugar:
package MyApp::User;
use Moose;
with 'My::Role';
β οΈ and this is important β don't use "MooseX" in the name for such packages. π
π New Types π
Another common Moose extension is a new type for the Moose type system. In this case you simply create a type in your module. When people load your module, the type is created, and after that they can refer to it by name. The MooseX::Types::URI and MooseX::Types::DateTime distributions are two good examples of how this works β and both of them build on top of the MooseX::Types extension. π
π ROLES VS TRAITS VS SUBCLASSES π
okay this part is so important so pay attention bestie. Roles and traits are the same thing. A trait is simply a role applied to an instance. The only thing that may distinguish the two is that a trait can be packaged in a way that lets Moose resolve a short name to a class name. In other words, with a trait, the caller can refer to it by a short name like "Big", and Moose will resolve it to a class like "MooseX::Embiggen::Meta::Attribute::Role::Big". magic. β¨
See Moose::Cookbook::Meta::Labeled_AttributeTrait and Moose::Cookbook::Meta::Table_MetaclassTrait for examples of traits in action. In particular, both of these recipes demonstrate the trait resolution mechanism. π
Implementing an extension as a (set of) metaclass or base object role(s) will make your extension more cooperative. Why? Because it is hard for an end-user to effectively combine together multiple metaclass subclassesβ¦ but it is very, very easy to combine roles. periodt. π
π still with us? good, because there's more β this was just part 1, and more parts follow! π¦
π USING YOUR EXTENSION π
okay so you made an extension, slay, but likeβ¦ how do people actually use it? bestie there are a bunch of ways to apply one, and sometimes you can offer several of them at once. pick your fighter π
β¨ Extensions as Metaclass Traits β¨
if your extension ships as a trait, you can just tell your people "put it in a list of traits, love u". currently this only works for (class) metaclass and attribute metaclass traits:
use Moose -traits => [ 'Big', 'Blue' ];
has 'animal' => (
traits => [ 'Big', 'Blue' ],
...
);
but if your extension touches any other metaclass, or the base object class? yeah no, the trait mechanism isn't available to you there. it's giving limited, ngl.
the glow-up though? the trait mechanism makes it so obvious where a trait got applied in the code, and the consumer gets fine-grained control over what it lands on. especially with attribute traits β you can slap a trait on literally one single attribute in a class. iconic control freak behaviour, we love it π
πΈ Extensions as Metaclass (and Base Object) Roles πΈ
doing your extensions as metaclass roles makes them easy to apply and cooperative with other role-based metaclass extensions. bestie behaviour fr fr.
same energy as a subclass: you're probably gonna wanna package your extensions for consumption with a single module that uses Moose::Exporter. but in this case you'll use Moose::Util::MetaRole to apply all your roles. the whole point of that module is that it preserves any subclassing or roles already applied to the user's metaclasses. meaning your extension is cooperative by default, and people using it can stack it with other role-based extensions no problem. and honestly, most uses of Moose::Util::MetaRole can be handled by Moose::Exporter directly β go read the Moose::Exporter docs, iykyk.
package MooseX::Embiggen;
use Moose::Exporter;
use MooseX::Embiggen::Role::Meta::Class;
use MooseX::Embiggen::Role::Meta::Attribute;
use MooseX::Embiggen::Role::Meta::Method::Constructor;
use MooseX::Embiggen::Role::Object;
Moose::Exporter->setup_import_methods(
class_metaroles => {
class => ['MooseX::Embiggen::Role::Meta::Class'],
attribute => ['MooseX::Embiggen::Role::Meta::Attribute'],
constructor =>
['MooseX::Embiggen::Role::Meta::Method::Constructor'],
},
base_class_roles => ['MooseX::Embiggen::Role::Object'],
);
see how that works? you can use Moose::Util::MetaRole to apply roles to any metaclass, plus the base object class. and if some other extension already applied its own roles? they get preserved when yours comes in, and vice versa. mutual respect, mutual slay π«Ά
π Providing Sugar π
with Moose::Exporter you can also export your very own sugar functions:
package MooseX::Embiggen;
use Moose::Exporter;
Moose::Exporter->setup_import_methods(
with_meta => ['embiggen'],
class_metaroles => {
class => ['MooseX::Embiggen::Role::Meta::Class'],
},
);
sub embiggen {
my $meta = shift;
$meta->embiggen(@_);
}
and then whoever consumes your extension gets to call your embiggen sub like it's nothing:
package Consumer;
use Moose;
use MooseX::Embiggen;
extends 'Thing';
embiggen ...;
and yeah, this combines with metaclass and base class roles super easily. best of both worlds, no cap β¨
π¦ More advanced extensions π¦
shipping your extension as a set of traits that get applied to the right metaobjects is easy⦠but sometimes it's just not enough. like, sometimes you don't just need a base object role, you need an actual base object class (because you gotta interact with existing systems that only give you a base class, ugh). to write extensions like that you'll need to provide a custom init_meta method in your exporter. for instance:
package MooseX::Embiggen;
use Moose::Exporter;
my ($import, $unimport, $init_meta) = Moose::Exporter->build_import_methods(
install => ['import', 'unimport'],
with_meta => ['embiggen'],
class_metaroles => {
class => ['MooseX::Embiggen::Role::Meta::Class'],
},
);
sub embiggen {
my $meta = shift;
$meta->embiggen(@_);
}
sub init_meta {
my $package = shift;
my %options = @_;
if (my $meta = Class::MOP::class_of($options{for_class})) {
if ($meta->isa('Class::MOP::Class')) {
my @supers = $meta->superclasses;
$meta->superclasses('MooseX::Embiggen::Base::Class')
if @supers == 1 && $supers[0] eq 'Moose::Object';
}
}
$package->$init_meta(%options);
}
in the previous examples init_meta was generated for you, but here you must override it to add extra functionality. some differences to clock π:
π§ "build_import_methods" instead of "setup_import_methods"
build_import_methods simply returns the import, unimport, and init_meta methods instead of installing them under the appropriate names. that way you can write your own methods that wrap the functionality Moose::Exporter gives you. the build_import_methods sub also takes an extra install parameter, which tells it to just go ahead and install these methods (since we don't need to modify them). easy π
π§ "sub init_meta"
next, we gotta write our init_meta wrapper. the important things to remember: it's called as a method, and %options needs to be passed through to the existing implementation. we call the base implementation using the $init_meta subroutine reference that build_import_methods handed back earlier. pass it along, don't drop it π
π§ Additional implementation
this extension sets a different default base object class. to do that, it first checks whether it's being applied to a class, then checks whether Moose::Object is that class's only superclass, and if so, replaces it with the superclass this extension requires.
β οΈ note that two extensions that do this same thing will not work together properly β the second extension to be loaded won't see Moose::Object as the base object, since it's already been overridden. this is exactly why using a base object role is recommended for the general case. do not try this at home unless you must π
this init_meta also works defensively, only applying its functionality if a metaclass already exists. that makes sure it doesn't break with legacy extensions that override the metaclass directly (and therefore must be the first extension to initialize the metaclass). this is likely not necessary, since almost no extensions work that way anymore, but it gives an extra level of protection. the common case of use Moose; use MooseX::Embiggen; is not affected regardless. so, like, no harm no foul πΈ
and this is just one example of what a custom init_meta can do. it can also stop an extension from being applied to a role, do other kinds of validation on the class being applied to, or pretty much anything that would otherwise live in an import method. the possibilities? endless, bestie.
π°οΈ LEGACY EXTENSION MECHANISMS π°οΈ
before Moose::Exporter and Moose::Util::MetaRole existed, there were a bunch of other ways to extend Moose. in general these were less cooperative, and only really worked well with a single extension. one extension at a time, no friends, tragic.
these methods include metaclass.pm, Moose::Policy (which uses metaclass.pm under the hood), and various hacks that do what Moose::Exporter does. please do not use these for your own extensions. respectfully, put them down π
also worth noting: if you write a cooperative extension, it should cooperate with older extensions β though older extensions generally don't cooperate with each other. messy. not our problem though π
π CONCLUSION π
if you can write your extension as one or more metaclass and base object roles, please consider doing so. and make sure to read the docs for Moose::Exporter and Moose::Util::MetaRole too. go read them. right now. i'll wait π«Ά
π AUTHORS π
- Stevan Little <stevan@cpan.org>
- Dave Rolsky <autarch@urth.org>
- Jesse Luehrs <doy@cpan.org>
- Shawn M Moore <sartak@cpan.org>
- ΧΧΧΧ Χ§ΧΧ'ΧΧ (Yuval Kogman) <nothingmuch@woobling.org>
- Karen Etheridge <ether@cpan.org>
- Florian Ragwitz <rafl@debian.org>
- Hans Dieter Pearcey <hdp@cpan.org>
- Chris Prather <chris@prather.org>
- Matt S Trout <mstrout@cpan.org>
absolute legends, every single one π
π COPYRIGHT AND LICENSE π
this software is copyright (c) 2006 by Infinity Interactive, Inc.
this is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
and that's a wrap on part 2, bestie!! πβ¨ this page came to you courtesy of perl v5.42.0, dated 2025-07-25, and it's the Moose::...Overview(3) page from the user contributed perl documentation. now go forth and write the most cooperative extension anyone's ever seen π
π¦π
π¦ where this page comes from
- fedora 43: perl-Moose 2.4000-4.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms