package Moose::Cookbook::Extending::Recipe1;

# ABSTRACT: Moose extension overview



=pod

=head1 NAME

Moose::Cookbook::Extending::Recipe1 - Moose extension overview

=head1 VERSION

version 2.0100

=head1 DESCRIPTION

Moose provides several ways in which extensions can hook into Moose
and change its behavior. Moose also has a lot of behavior that can be
changed. This recipe will provide an overview of each extension method
and give you some recommendations on what tools to use.

If you haven't yet read the recipes on metaclasses, go read those
first. You can't write Moose extensions without understanding the
metaclasses, and those recipes also demonstrate some basic extension
mechanisms, such as metaclass subclasses and traits.

=head2 Playing Nice With Others

One of the goals of this overview is to help you build extensions that
cooperate well with other extensions. This is especially important if
you plan to release your extension to CPAN.

Moose comes with several modules that exist to help your write
cooperative extensions. These are L<Moose::Exporter> and
L<Moose::Util::MetaRole>. By using these two modules, you will ensure
that your extension works with both the Moose core features and any
other CPAN extension using those modules.

=head1 PARTS OF Moose YOU CAN EXTEND

The types of things you might want to do in Moose extensions fall into
a few broad categories.

=head2 Metaclass Extensions

One way of extending Moose is by extending one or more Moose
metaclasses. For example, in L<Moose::Cookbook::Meta::Recipe4> we saw
a metaclass subclass that added a C<table> 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<MooseX::AttributeHelpers>
distribution provides a new attribute metaclass that lets you delegate
behavior to a non-object attribute (a hashref or simple number).

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.

When your extensions are implemented as roles, you can apply them with
the L<Moose::Util::MetaRole> module.

=head2 Providing Sugar Functions

As part of a metaclass extension, you may also want to provide some
sugar functions, just like L<Moose.pm|Moose> does. Moose provides a
helper module called L<Moose::Exporter> that makes this much
simpler. We will be use L<Moose::Exporter> in several of the extension
recipes.

=head2 Object Class Extensions

Another common Moose extension technique is to change the default
object class's behavior. For example, the L<MooseX::Singleton>
extension changes the behavior of your objects so that they are
singletons. The L<MooseX::StrictConstructor> extension 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
L<Moose::Meta::Instance>, L<Moose::Meta::Method::Constructor>, and
L<Moose::Meta::Method::Destructor> objects.

The L<Moose::Util::MetaRole> module lets you apply roles to the base
object class, as well as the meta classes just mentioned.

=head2 Providing a Role

Some extensions come in the form of a role for you to consume. The
L<MooseX::Object::Pluggable> extension is a great example of this. In
fact, despite the C<MooseX> name, it does not actually change anything
about Moose's behavior. Instead, it is just a role that an object
which wants to be pluggable can consume.

If you are 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 C<with> sugar:

   package MyApp::User;

   use Moose;

   with 'MooseX::My::Role';

=head2 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 they can refer to it
by name after that. The L<MooseX::Types::URI> and
L<MooseX::Types::DateTime> distributions are two good examples of how
this works. These both build on top of the L<MooseX::Types> extension.

=head1 ROLES VS TRAITS VS SUBCLASSES

It is important to understand that B<roles and traits are the same thing>. A
trait is simply a role applied to a 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 C<MooseX::Embiggen::Meta::Attribute::Role::Big>.

See L<Moose::Cookbook::Meta::Recipe3> and
L<Moose::Cookbook::Meta::Recipe5> 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. It is hard for an
end-user to effectively combine together multiple metaclass
subclasses, but it is very easy to combine roles.

=head1 USING YOUR EXTENSION

There are a number of ways in which an extension can be applied. In
some cases you can provide multiple ways of consuming your extension.

=head2 Extensions as Metaclass Traits

If your extension is available as a trait, you can ask end users to
simply specify it in a list of traits. Currently, this only works for
(class) metaclass and attribute metaclass traits:

  use Moose -traits => [ 'Big', 'Blue' ];

  has 'animal' => (
      traits => [ 'Big', 'Blue' ],
      ...
  );

If your extension applies to any other metaclass, or the object base
class, you cannot use the trait mechanism.

The benefit of the trait mechanism is that is very easy to see where a
trait is applied in the code, and consumers have fine-grained control
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<metaclass> 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<Moose::Exporter>
to re-export the L<Moose.pm|Moose> sugar function. With
L<Moose::Exporter>, if your exporting class has an C<init_meta>
method, L<Moose::Exporter> makes sure that this C<init_meta> method
gets called when your class is imported.

Then in your C<init_meta> 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<init_meta> 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
easy to apply, and cooperative with other role-based extensions for
metaclasses.

Just as with a subclass, you will probably want to package your
extensions for consumption with a single module that uses
L<Moose::Exporter>. However, in this case, you will use
L<Moose::Util::MetaRole> to apply all of your roles. The advantage of
using this module is that I<it preserves any subclassing or roles
already applied to the user's metaclasses>. This means that your
extension is cooperative I<by default>, and consumers of your
extension can easily use it with other role-based extensions. Most
uses of L<Moose::Util::MetaRole> can be handled by L<Moose::Exporter>
directly; see the L<Moose::Exporter> docs.

  package MooseX::Embiggen;

  use Moose ();
  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;

  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'],
      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<Moose::Util::MetaRole>
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
preserved when your extension applies its roles, and vice versa.

=head2 Providing Sugar

With L<Moose::Exporter>, you can also export your own sugar functions,
as well as those from other modules:

  package MooseX::Embiggen;

  use Moose ();
  use Moose::Exporter;

  Moose::Exporter->setup_import_methods(
      with_meta => ['embiggen'],
      also      => 'Moose',
  );

  sub embiggen {
      my $meta = shift;
      $meta->embiggen(@_);
  }

And then the consumer of your extension can use your C<embiggen> sub:

  package Consumer;

  use MooseX::Embiggen;

  extends 'Thing';

  embiggen ...;

This can be combined with metaclass and base class roles quite easily.

=head1 LEGACY EXTENSION MECHANISMS

Before the existence of L<Moose::Exporter> and
L<Moose::Util::MetaRole>, there were a number of other ways to extend
Moose. In general, these methods were less cooperative, and only
worked well with a single extension.

These methods include L<metaclass.pm|metaclass>, L<Moose::Policy>
(which uses L<metaclass.pm|metaclass> under the hood), and various
hacks to do what L<Moose::Exporter> does. Please do not use these for
your own extensions.

Note that if you write a cooperative extension, it should cooperate
with older extensions, though older extensions generally do not
cooperate with each other.

=head1 CONCLUSION

If you can write your extension as one or more metaclass and base
object roles, please consider doing so. Make sure to read the docs for
L<Moose::Exporter> and L<Moose::Util::MetaRole> as well.

=head1 AUTHOR

Stevan Little <stevan@iinteractive.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 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.

=cut


__END__


