From: Dave Rolsky Date: Fri, 30 Sep 2011 17:26:48 +0000 (-0500) Subject: Update to modernize recommendations and make example code use modern APIs X-Git-Tag: 2.0500~86 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMoose.git;a=commitdiff_plain;h=546a18e9816515d23c9e5350dfe2b83fc6036f5b Update to modernize recommendations and make example code use modern APIs --- diff --git a/lib/Moose/Cookbook/Extending/Recipe1.pod b/lib/Moose/Cookbook/Extending/Recipe1.pod index 62bfc4a..6b2cb28 100644 --- a/lib/Moose/Cookbook/Extending/Recipe1.pod +++ b/lib/Moose/Cookbook/Extending/Recipe1.pod @@ -39,20 +39,19 @@ a few broad categories. =head2 Metaclass Extensions One way of extending Moose is by extending one or more Moose -metaclasses. For example, in L we saw -a metaclass subclass that added a C attribute to the +metaclasses. For example, in L we saw +a metaclass role that added a C
attribute to the metaclass. If you were writing an ORM, this would be a logical extension. Many of the Moose extensions on CPAN work by providing an attribute -metaclass extension. For example, the L module +metaclass role. For example, the L module provides an attribute metaclass trait that lets you specify aliases to install for methods and attribute accessors. -A metaclass extension can be packaged as a subclass or a -role/trait. If you can, we recommend using traits instead of -subclasses, since it's much easier to combine disparate traits than it -is to combine a bunch of subclasses. +A metaclass extension can be packaged as a role/trait or a subclass. If you +can, we recommend using traits instead of subclasses, since it's much easier +to combine disparate traits than it is to combine a bunch of subclasses. When your extensions are implemented as roles, you can apply them with the L module. @@ -67,15 +66,15 @@ recipes. =head2 Object Class Extensions -Another common Moose extension technique is to change the default -object class's behavior. For example, the L -extension changes the behavior of your objects so that they are -singletons. The L extension makes the -constructor reject arguments which don't match its attributes. +Another common Moose extension technique is to change the default object +class's behavior. As with metaclass extensions, this can be done with a +role/trait or with a subclass. For example, L +extension applies a trait that makes the constructor reject arguments which +don't match its attributes. Object class extensions often include metaclass extensions as well. In particular, if you want your object extension to work when a class is -made immutable, you may need to extend some or all of the +made immutable, you may need to modify the behavior of some or all of the L, L, and L objects. @@ -98,7 +97,9 @@ be used via the normal C sugar: use Moose; - with 'MooseX::My::Role'; + with 'My::Role'; + +Don't use "MooseX" in the name for such packages. =head2 New Types @@ -155,51 +156,6 @@ over what the trait applies to. This is especially true for attribute traits, where you can apply the trait to just one attribute in a class. -=head2 Extensions as Metaclass (and Base Object) Subclasses - -Moose does not provide any simple APIs for consumers to use a subclass -extension, except for attribute metaclasses. The attribute declaration -options include a C option a consumer of your extension can -use to specify your subclass. - -This is one reason why implementing an extension as a subclass can be -a poor choice. However, you can force the use of certain subclasses at -import time by calling C<< Moose->init_meta >> for the caller, and -providing an alternate metaclass or base object class. - -If you do want to do this, you should look at using L -to re-export the L sugar function. With -L, if your exporting class has an C -method, L makes sure that this C method -gets called when your class is imported. - -Then in your C you can arrange for the caller to use your -subclasses: - - package MooseX::Embiggen; - - use Moose (); - use Moose::Exporter; - - use MooseX::Embiggen::Meta::Class; - use MooseX::Embiggen::Object; - - Moose::Exporter->setup_import_methods( also => 'Moose' ); - - sub init_meta { - shift; # just your package name - my %options = @_; - - return Moose->init_meta( - for_class => $options{for_class}, - metaclass => 'MooseX::Embiggen::Meta::Class', - base_class => 'MooseX::Embiggen::Object', - ); - } - -NOTE: Make sure that your C returns the metaclass object, just as -C<< Moose->init_meta >> does. - =head2 Extensions as Metaclass (and Base Object) Roles Implementing your extensions as metaclass roles makes your extensions @@ -219,7 +175,9 @@ directly; see the L docs. package MooseX::Embiggen; - use Moose (); + use strict; + use warnings; + use Moose::Exporter; use MooseX::Embiggen::Role::Meta::Class; @@ -227,23 +185,16 @@ directly; see the L docs. use MooseX::Embiggen::Role::Meta::Method::Constructor; use MooseX::Embiggen::Role::Object; - my ( $import, $unimport, $init_meta ) = Moose::Exporter->build_import_methods( - also => ['Moose'], metaclass_roles => - ['MooseX::Embiggen::Role::Meta::Class'], - attribute_metaclass_roles => ['MooseX::Embiggen::Role::Meta::Attribute'], - constructor_class_roles => - ['MooseX::Embiggen::Role::Meta::Method::Constructor'], + 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'], - install => [qw(import unimport)], ); - sub init_meta { - my $package = shift; - my %options = @_; - Moose->init_meta(%options); - return $package->$init_meta(%options); - } - As you can see from this example, you can use L to apply roles to any metaclass, as well as the base object class. If some other extension has already applied its own roles, they will be @@ -251,17 +202,20 @@ preserved when your extension applies its roles, and vice versa. =head2 Providing Sugar -With L, you can also export your own sugar functions, -as well as those from other modules: +With L, you can also export your own sugar functions: package MooseX::Embiggen; - use Moose (); + use strict; + use warnings; + use Moose::Exporter; Moose::Exporter->setup_import_methods( - with_meta => ['embiggen'], - also => 'Moose', + with_meta => ['embiggen'], + class_metaroles => { + class => ['MooseX::Embiggen::Role::Meta::Class'], + }, ); sub embiggen { @@ -281,6 +235,54 @@ And then the consumer of your extension can use your C sub: This can be combined with metaclass and base class roles quite easily. +=head2 Extensions as Metaclass (and Base Object) Subclasses + +B. + +Moose does not provide any simple APIs for consumers to use a subclass +extension, except for attribute metaclasses. The attribute declaration +options include a C option a consumer of your extension can +use to specify your subclass. + +This is one reason why implementing an extension as a subclass can be +a poor choice. However, you can force the use of certain subclasses at +import time by calling C<< Moose->init_meta >> for the caller, and +providing an alternate metaclass or base object class. + +If you do want to do this, you should look at using L +to re-export the L sugar function. With +L, if your exporting class has an C +method, L makes sure that this C method +gets called when your class is imported. + +Then in your C you can arrange for the caller to use your +subclasses: + + package MooseX::Embiggen; + + use Moose (); + use Moose::Exporter; + + use MooseX::Embiggen::Meta::Class; + use MooseX::Embiggen::Object; + + Moose::Exporter->setup_import_methods( also => 'Moose' ); + + sub init_meta { + shift; # just your package name + my %options = @_; + + return Moose->init_meta( + for_class => $options{for_class}, + metaclass => 'MooseX::Embiggen::Meta::Class', + base_class => 'MooseX::Embiggen::Object', + ); + } + +NOTE: Make sure that your C returns the metaclass object, just as +C<< Moose->init_meta >> does. + =head1 LEGACY EXTENSION MECHANISMS Before the existence of L and