summaryrefslogtreecommitdiff
path: root/lib/Moose/Cookbook/Meta
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Moose/Cookbook/Meta')
-rw-r--r--lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod304
-rw-r--r--lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod325
-rw-r--r--lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod224
-rw-r--r--lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod156
-rw-r--r--lib/Moose/Cookbook/Meta/WhyMeta.pod117
5 files changed, 1126 insertions, 0 deletions
diff --git a/lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod b/lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod
new file mode 100644
index 0000000..9ca9f68
--- /dev/null
+++ b/lib/Moose/Cookbook/Meta/GlobRef_InstanceMetaclass.pod
@@ -0,0 +1,304 @@
+# PODNAME: Moose::Cookbook::Meta::GlobRef_InstanceMetaclass
+# ABSTRACT: Creating a glob reference meta-instance class
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Moose::Cookbook::Meta::GlobRef_InstanceMetaclass - Creating a glob reference meta-instance class
+
+=head1 VERSION
+
+version 2.1405
+
+=head1 SYNOPSIS
+
+ package My::Meta::Instance;
+
+ use Scalar::Util qw( weaken );
+ use Symbol qw( gensym );
+
+ use Moose::Role;
+
+ sub create_instance {
+ my $self = shift;
+ my $sym = gensym();
+ bless $sym, $self->_class_name;
+ }
+
+ sub clone_instance {
+ my ( $self, $instance ) = @_;
+
+ my $new_sym = gensym();
+ %{*$new_sym} = %{*$instance};
+
+ bless $new_sym, $self->_class_name;
+ }
+
+ sub get_slot_value {
+ my ( $self, $instance, $slot_name ) = @_;
+ return *$instance->{$slot_name};
+ }
+
+ sub set_slot_value {
+ my ( $self, $instance, $slot_name, $value ) = @_;
+ *$instance->{$slot_name} = $value;
+ }
+
+ sub deinitialize_slot {
+ my ( $self, $instance, $slot_name ) = @_;
+ delete *$instance->{$slot_name};
+ }
+
+ sub is_slot_initialized {
+ my ( $self, $instance, $slot_name ) = @_;
+ exists *$instance->{$slot_name};
+ }
+
+ sub weaken_slot_value {
+ my ( $self, $instance, $slot_name ) = @_;
+ weaken *$instance->{$slot_name};
+ }
+
+ sub inline_create_instance {
+ my ( $self, $class_variable ) = @_;
+ return 'do { my $sym = Symbol::gensym(); bless $sym, ' . $class_variable . ' }';
+ }
+
+ sub inline_slot_access {
+ my ( $self, $instance, $slot_name ) = @_;
+ return '*{' . $instance . '}->{' . $slot_name . '}';
+ }
+
+ package MyApp::User;
+
+ use Moose;
+ Moose::Util::MetaRole::apply_metaroles(
+ for => __PACKAGE__,
+ class_metaroles => {
+ instance => ['My::Meta::Instance'],
+ },
+ );
+
+ has 'name' => (
+ is => 'rw',
+ isa => 'Str',
+ );
+
+ has 'email' => (
+ is => 'rw',
+ isa => 'Str',
+ );
+
+=head1 DESCRIPTION
+
+This recipe shows how to build your own meta-instance. The meta
+instance is the metaclass that creates object instances and helps
+manages access to attribute slots.
+
+In this example, we're creating a meta-instance that is based on a
+glob reference rather than a hash reference. This example is largely
+based on the Piotr Roszatycki's L<MooseX::GlobRef> module.
+
+Our extension is a role which will be applied to L<Moose::Meta::Instance>,
+which creates hash reference based objects. We need to override all the methods
+which make assumptions about the object's data structure.
+
+The first method we override is C<create_instance>:
+
+ sub create_instance {
+ my $self = shift;
+ my $sym = gensym();
+ bless $sym, $self->_class_name;
+ }
+
+This returns an glob reference which has been blessed into our
+meta-instance's associated class.
+
+We also override C<clone_instance> to create a new array reference:
+
+ sub clone_instance {
+ my ( $self, $instance ) = @_;
+
+ my $new_sym = gensym();
+ %{*$new_sym} = %{*$instance};
+
+ bless $new_sym, $self->_class_name;
+ }
+
+After that, we have a series of methods which mediate access to the
+object's slots (attributes are stored in "slots"). In the default
+instance class, these expect the object to be a hash reference, but we
+need to change this to expect a glob reference instead.
+
+ sub get_slot_value {
+ my ( $self, $instance, $slot_name ) = @_;
+ *$instance->{$slot_name};
+ }
+
+This level of indirection probably makes our instance class I<slower>
+than the default. However, when attribute access is inlined, this
+lookup will be cached:
+
+ sub inline_slot_access {
+ my ( $self, $instance, $slot_name ) = @_;
+ return '*{' . $instance . '}->{' . $slot_name . '}';
+ }
+
+The code snippet that the C<inline_slot_access> method returns will
+get C<eval>'d once per attribute.
+
+Finally, we use this meta-instance in our C<MyApp::User> class:
+
+ Moose::Util::MetaRole::apply_metaroles(
+ for => __PACKAGE__,
+ class_metaroles => {
+ instance => ['My::Meta::Instance'],
+ },
+ );
+
+We actually don't recommend the use of L<Moose::Util::MetaRole> directly in
+your class in most cases. Typically, this would be provided by a
+L<Moose::Exporter>-based module which handles applying the role for you.
+
+=head1 CONCLUSION
+
+This recipe shows how to create your own meta-instance class. It's
+unlikely that you'll need to do this yourself, but it's interesting to
+take a peek at how Moose works under the hood.
+
+=head1 SEE ALSO
+
+There are a few meta-instance class extensions on CPAN:
+
+=over 4
+
+=item * L<MooseX::Singleton>
+
+This module extends the instance class in order to ensure that the
+object is a singleton. The instance it uses is still a blessed hash
+reference.
+
+=item * L<MooseX::GlobRef>
+
+This module makes the instance a blessed glob reference. This lets you
+use a handle as an object instance.
+
+=back
+
+=begin testing
+
+{
+ package MyApp::Employee;
+
+ use Moose;
+ extends 'MyApp::User';
+
+ has 'employee_number' => ( is => 'rw' );
+}
+
+for my $x ( 0 .. 1 ) {
+ MyApp::User->meta->make_immutable if $x;
+
+ my $user = MyApp::User->new(
+ name => 'Faye',
+ email => 'faye@example.com',
+ );
+
+ ok( eval { *{$user} }, 'user object is an glob ref with some values' );
+
+ is( $user->name, 'Faye', 'check name' );
+ is( $user->email, 'faye@example.com', 'check email' );
+
+ $user->name('Ralph');
+ is( $user->name, 'Ralph', 'check name after changing it' );
+
+ $user->email('ralph@example.com');
+ is( $user->email, 'ralph@example.com', 'check email after changing it' );
+}
+
+for my $x ( 0 .. 1 ) {
+ MyApp::Employee->meta->make_immutable if $x;
+
+ my $emp = MyApp::Employee->new(
+ name => 'Faye',
+ email => 'faye@example.com',
+ employee_number => $x,
+ );
+
+ ok( eval { *{$emp} }, 'employee object is an glob ref with some values' );
+
+ is( $emp->name, 'Faye', 'check name' );
+ is( $emp->email, 'faye@example.com', 'check email' );
+ is( $emp->employee_number, $x, 'check employee_number' );
+
+ $emp->name('Ralph');
+ is( $emp->name, 'Ralph', 'check name after changing it' );
+
+ $emp->email('ralph@example.com');
+ is( $emp->email, 'ralph@example.com', 'check email after changing it' );
+
+ $emp->employee_number(42);
+ is( $emp->employee_number, 42, 'check employee_number after changing it' );
+}
+
+=end testing
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Stevan Little <stevan.little@iinteractive.com>
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=item *
+
+Shawn M Moore <code@sartak.org>
+
+=item *
+
+יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Florian Ragwitz <rafl@debian.org>
+
+=item *
+
+Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=item *
+
+Chris Prather <chris@prather.org>
+
+=item *
+
+Matt S Trout <mst@shadowcat.co.uk>
+
+=back
+
+=head1 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.
+
+=cut
diff --git a/lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod b/lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod
new file mode 100644
index 0000000..cebe091
--- /dev/null
+++ b/lib/Moose/Cookbook/Meta/Labeled_AttributeTrait.pod
@@ -0,0 +1,325 @@
+# PODNAME: Moose::Cookbook::Meta::Labeled_AttributeTrait
+# ABSTRACT: Labels implemented via attribute traits
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Moose::Cookbook::Meta::Labeled_AttributeTrait - Labels implemented via attribute traits
+
+=head1 VERSION
+
+version 2.1405
+
+=head1 SYNOPSIS
+
+ package MyApp::Meta::Attribute::Trait::Labeled;
+ use Moose::Role;
+ Moose::Util::meta_attribute_alias('Labeled');
+
+ has label => (
+ is => 'rw',
+ isa => 'Str',
+ predicate => 'has_label',
+ );
+
+ package MyApp::Website;
+ use Moose;
+
+ has url => (
+ traits => [qw/Labeled/],
+ is => 'rw',
+ isa => 'Str',
+ label => "The site's URL",
+ );
+
+ has name => (
+ is => 'rw',
+ isa => 'Str',
+ );
+
+ sub dump {
+ my $self = shift;
+
+ my $meta = $self->meta;
+
+ my $dump = '';
+
+ for my $attribute ( map { $meta->get_attribute($_) }
+ sort $meta->get_attribute_list ) {
+
+ if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled')
+ && $attribute->has_label ) {
+ $dump .= $attribute->label;
+ }
+ else {
+ $dump .= $attribute->name;
+ }
+
+ my $reader = $attribute->get_read_method;
+ $dump .= ": " . $self->$reader . "\n";
+ }
+
+ return $dump;
+ }
+
+ package main;
+
+ my $app = MyApp::Website->new( url => "http://google.com", name => "Google" );
+
+=head1 SUMMARY
+
+In this recipe, we begin to delve into the wonder of meta-programming.
+Some readers may scoff and claim that this is the arena of only the
+most twisted Moose developers. Absolutely not! Any sufficiently
+twisted developer can benefit greatly from going more meta.
+
+Our goal is to allow each attribute to have a human-readable "label"
+attached to it. Such labels would be used when showing data to an end
+user. In this recipe we label the C<url> attribute with "The site's
+URL" and create a simple method showing how to use that label.
+
+=head1 META-ATTRIBUTE OBJECTS
+
+All the attributes of a Moose-based object are actually objects themselves.
+These objects have methods and attributes. Let's look at a concrete example.
+
+ has 'x' => ( isa => 'Int', is => 'ro' );
+ has 'y' => ( isa => 'Int', is => 'rw' );
+
+Internally, the metaclass for C<Point> has two L<Moose::Meta::Attribute>
+objects. There are several methods for getting meta-attributes out of a
+metaclass, one of which is C<get_attribute_list>. This method is called on the
+metaclass object.
+
+The C<get_attribute_list> method returns a list of attribute names. You can
+then use C<get_attribute> to get the L<Moose::Meta::Attribute> object itself.
+
+Once you have this meta-attribute object, you can call methods on it like
+this:
+
+ print $point->meta->get_attribute('x')->type_constraint;
+ => Int
+
+To add a label to our attributes there are two steps. First, we need a new
+attribute metaclass trait that can store a label for an attribute. Second, we
+need to apply that trait to our attributes.
+
+=head1 TRAITS
+
+Roles that apply to metaclasses have a special name: traits. Don't let
+the change in nomenclature fool you, B<traits are just roles>.
+
+L<Moose/has> allows you to pass a C<traits> parameter for an
+attribute. This parameter takes a list of trait names which are
+composed into an anonymous metaclass, and that anonymous metaclass is
+used for the attribute.
+
+Yes, we still have lots of metaclasses in the background, but they're
+managed by Moose for you.
+
+Traits can do anything roles can do. They can add or refine
+attributes, wrap methods, provide more methods, define an interface,
+etc. The only difference is that you're now changing the attribute
+metaclass instead of a user-level class.
+
+=head1 DISSECTION
+
+We start by creating a package for our trait.
+
+ package MyApp::Meta::Attribute::Trait::Labeled;
+ use Moose::Role;
+
+ has label => (
+ is => 'rw',
+ isa => 'Str',
+ predicate => 'has_label',
+ );
+
+You can see that a trait is just a L<Moose::Role>. In this case, our role
+contains a single attribute, C<label>. Any attribute which does this trait
+will now have a label.
+
+We also register our trait with Moose:
+
+ Moose::Util::meta_attribute_alias('Labeled');
+
+This allows Moose to find our trait by the short name C<Labeled> when passed
+to the C<traits> attribute option, rather than requiring the full package
+name to be specified.
+
+Finally, we pass our trait when defining an attribute:
+
+ has url => (
+ traits => [qw/Labeled/],
+ is => 'rw',
+ isa => 'Str',
+ label => "The site's URL",
+ );
+
+The C<traits> parameter contains a list of trait names. Moose will build an
+anonymous attribute metaclass from these traits and use it for this
+attribute.
+
+The reason that we can pass the name C<Labeled>, instead of
+C<MyApp::Meta::Attribute::Trait::Labeled>, is because of the
+C<register_implementation> code we touched on previously.
+
+When you pass a metaclass to C<has>, it will take the name you provide and
+prefix it with C<Moose::Meta::Attribute::Custom::Trait::>. Then it calls
+C<register_implementation> in the package. In this case, that means Moose ends
+up calling
+C<Moose::Meta::Attribute::Custom::Trait::Labeled::register_implementation>.
+
+If this function exists, it should return the I<real> trait's package
+name. This is exactly what our code does, returning
+C<MyApp::Meta::Attribute::Trait::Labeled>. This is a little convoluted, and if
+you don't like it, you can always use the fully-qualified name.
+
+We can access this meta-attribute and its label like this:
+
+ $website->meta->get_attribute('url')->label()
+
+ MyApp::Website->meta->get_attribute('url')->label()
+
+We also have a regular attribute, C<name>:
+
+ has name => (
+ is => 'rw',
+ isa => 'Str',
+ );
+
+Finally, we have a C<dump> method, which creates a human-readable
+representation of a C<MyApp::Website> object. It will use an attribute's label
+if it has one.
+
+ sub dump {
+ my $self = shift;
+
+ my $meta = $self->meta;
+
+ my $dump = '';
+
+ for my $attribute ( map { $meta->get_attribute($_) }
+ sort $meta->get_attribute_list ) {
+
+ if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled')
+ && $attribute->has_label ) {
+ $dump .= $attribute->label;
+ }
+
+This is a bit of defensive code. We cannot depend on every meta-attribute
+having a label. Even if we define one for every attribute in our class, a
+subclass may neglect to do so. Or a superclass could add an attribute without
+a label.
+
+We also check that the attribute has a label using the predicate we
+defined. We could instead make the label C<required>. If we have a label, we
+use it, otherwise we use the attribute name:
+
+ else {
+ $dump .= $attribute->name;
+ }
+
+ my $reader = $attribute->get_read_method;
+ $dump .= ": " . $self->$reader . "\n";
+ }
+
+ return $dump;
+ }
+
+The C<get_read_method> is part of the L<Moose::Meta::Attribute> API. It
+returns the name of a method that can read the attribute's value, I<when
+called on the real object> (don't call this on the meta-attribute).
+
+=head1 CONCLUSION
+
+You might wonder why you'd bother with all this. You could just hardcode "The
+Site's URL" in the C<dump> method. But we want to avoid repetition. If you
+need the label once, you may need it elsewhere, maybe in the C<as_form> method
+you write next.
+
+Associating a label with an attribute just makes sense! The label is a piece
+of information I<about> the attribute.
+
+It's also important to realize that this was a trivial example. You can make
+much more powerful metaclasses that I<do> things, as opposed to just storing
+some more information. For example, you could implement a metaclass that
+expires attributes after a certain amount of time:
+
+ has site_cache => (
+ traits => ['TimedExpiry'],
+ expires_after => { hours => 1 },
+ refresh_with => sub { get( $_[0]->url ) },
+ isa => 'Str',
+ is => 'ro',
+ );
+
+The sky's the limit!
+
+=for testing my $app
+ = MyApp::Website->new( url => 'http://google.com', name => 'Google' );
+is(
+ $app->dump, q{name: Google
+The site's URL: http://google.com
+}, '... got the expected dump value'
+);
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Stevan Little <stevan.little@iinteractive.com>
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=item *
+
+Shawn M Moore <code@sartak.org>
+
+=item *
+
+יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Florian Ragwitz <rafl@debian.org>
+
+=item *
+
+Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=item *
+
+Chris Prather <chris@prather.org>
+
+=item *
+
+Matt S Trout <mst@shadowcat.co.uk>
+
+=back
+
+=head1 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.
+
+=cut
diff --git a/lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod b/lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod
new file mode 100644
index 0000000..dab0a38
--- /dev/null
+++ b/lib/Moose/Cookbook/Meta/PrivateOrPublic_MethodMetaclass.pod
@@ -0,0 +1,224 @@
+# PODNAME: Moose::Cookbook::Meta::PrivateOrPublic_MethodMetaclass
+# ABSTRACT: A method metaclass for marking methods public or private
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Moose::Cookbook::Meta::PrivateOrPublic_MethodMetaclass - A method metaclass for marking methods public or private
+
+=head1 VERSION
+
+version 2.1405
+
+=head1 SYNOPSIS
+
+ package MyApp::Meta::Method::PrivateOrPublic;
+
+ use Moose;
+ use Moose::Util::TypeConstraints;
+
+ extends 'Moose::Meta::Method';
+
+ has '_policy' => (
+ is => 'ro',
+ isa => enum( [ qw( public private ) ] ),
+ default => 'public',
+ init_arg => 'policy',
+ );
+
+ sub new {
+ my $class = shift;
+ my %options = @_;
+
+ my $self = $class->SUPER::wrap(%options);
+
+ $self->{_policy} = $options{policy};
+
+ $self->_add_policy_wrapper;
+
+ return $self;
+ }
+
+ sub _add_policy_wrapper {
+ my $self = shift;
+
+ return if $self->is_public;
+
+ my $name = $self->name;
+ my $package = $self->package_name;
+ my $real_body = $self->body;
+
+ my $body = sub {
+ die "The $package\::$name method is private"
+ unless ( scalar caller() ) eq $package;
+
+ goto &{$real_body};
+ };
+
+ $self->{body} = $body;
+ }
+
+ sub is_public { $_[0]->_policy eq 'public' }
+ sub is_private { $_[0]->_policy eq 'private' }
+
+ package MyApp::User;
+
+ use Moose;
+
+ has 'password' => ( is => 'rw' );
+
+ __PACKAGE__->meta()->add_method(
+ '_reset_password',
+ MyApp::Meta::Method::PrivateOrPublic->new(
+ name => '_reset_password',
+ package_name => __PACKAGE__,
+ body => sub { $_[0]->password('reset') },
+ policy => 'private',
+ )
+ );
+
+=head1 DESCRIPTION
+
+This example shows a custom method metaclass that models public versus
+private methods. If a method is defined as private, it adds a wrapper
+around the method which dies unless it is called from the class where
+it was defined.
+
+The way the method is added to the class is rather ugly. If we wanted
+to make this a real feature, we'd probably want to add some sort of
+sugar to allow us to declare private methods, but that is beyond the
+scope of this recipe. See the Extending recipes for more on this
+topic.
+
+The core of our custom class is the C<policy> attribute, and
+C<_add_policy_wrapper> method.
+
+You'll note that we have to explicitly set the C<policy> attribute in
+our constructor:
+
+ $self->{_policy} = $options{policy};
+
+That is necessary because Moose metaclasses do not use the meta API to
+create objects. Most Moose classes have a custom "inlined" constructor
+for speed.
+
+In this particular case, our parent class's constructor is the C<wrap>
+method. We call that to build our object, but it does not include
+subclass-specific attributes.
+
+The C<_add_policy_wrapper> method is where the real work is done. If
+the method is private, we construct a wrapper around the real
+subroutine which checks that the caller matches the package in which
+the subroutine was created.
+
+If they don't match, it dies. If they do match, the real method is
+called. We use C<goto> so that the wrapper does not show up in the
+call stack.
+
+Finally, we replace the value of C<< $self->{body} >>. This is another
+case where we have to do something a bit gross because Moose does not
+use Moose for its own implementation.
+
+When we pass this method object to the metaclass's C<add_method>
+method, it will take the method body and make it available in the
+class.
+
+Finally, when we retrieve these methods via the introspection API, we
+can call the C<is_public> and C<is_private> methods on them to get
+more information about the method.
+
+=head1 SUMMARY
+
+A custom method metaclass lets us add both behavior and
+meta-information to methods. Unfortunately, because the Perl
+interpreter does not provide easy hooks into method declaration, the
+API we have for adding these methods is not very pretty.
+
+That can be improved with custom Moose-like sugar, or even by using a
+tool like L<Devel::Declare> to create full-blown new keywords in Perl.
+
+=begin testing
+
+package main;
+use strict;
+use warnings;
+
+use Test::Fatal;
+
+my $user = MyApp::User->new( password => 'foo!' );
+
+like( exception { $user->_reset_password },
+qr/The MyApp::User::_reset_password method is private/,
+ '_reset_password method dies if called outside MyApp::User class');
+
+{
+ package MyApp::User;
+
+ sub run_reset { $_[0]->_reset_password }
+}
+
+$user->run_reset;
+
+is( $user->password, 'reset', 'password has been reset' );
+
+=end testing
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Stevan Little <stevan.little@iinteractive.com>
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=item *
+
+Shawn M Moore <code@sartak.org>
+
+=item *
+
+יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Florian Ragwitz <rafl@debian.org>
+
+=item *
+
+Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=item *
+
+Chris Prather <chris@prather.org>
+
+=item *
+
+Matt S Trout <mst@shadowcat.co.uk>
+
+=back
+
+=head1 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.
+
+=cut
diff --git a/lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod b/lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod
new file mode 100644
index 0000000..cf352e7
--- /dev/null
+++ b/lib/Moose/Cookbook/Meta/Table_MetaclassTrait.pod
@@ -0,0 +1,156 @@
+# PODNAME: Moose::Cookbook::Meta::Table_MetaclassTrait
+# ABSTRACT: Adding a "table" attribute as a metaclass trait
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Moose::Cookbook::Meta::Table_MetaclassTrait - Adding a "table" attribute as a metaclass trait
+
+=head1 VERSION
+
+version 2.1405
+
+=head1 SYNOPSIS
+
+ # in lib/MyApp/Meta/Class/Trait/HasTable.pm
+ package MyApp::Meta::Class::Trait::HasTable;
+ use Moose::Role;
+ Moose::Util::meta_class_alias('HasTable');
+
+ has table => (
+ is => 'rw',
+ isa => 'Str',
+ );
+
+ # in lib/MyApp/User.pm
+ package MyApp::User;
+ use Moose -traits => 'HasTable';
+
+ __PACKAGE__->meta->table('User');
+
+=head1 DESCRIPTION
+
+In this recipe, we'll create a class metaclass trait which has a "table"
+attribute. This trait is for classes associated with a DBMS table, as one
+might do for an ORM.
+
+In this example, the table name is just a string, but in a real ORM
+the table might be an object describing the table.
+
+=begin testing-SETUP
+
+BEGIN {
+ package MyApp::Meta::Class::Trait::HasTable;
+ use Moose::Role;
+ Moose::Util::meta_class_alias('HasTable');
+
+ has table => (
+ is => 'rw',
+ isa => 'Str',
+ );
+}
+
+=end testing-SETUP
+
+=head1 THE METACLASS TRAIT
+
+This really is as simple as the recipe L</SYNOPSIS> shows. The trick is
+getting your classes to use this metaclass, and providing some sort of sugar
+for declaring the table. This is covered in
+L<Moose::Cookbook::Extending::Debugging_BaseClassRole>, which shows how to
+make a module like C<Moose.pm> itself, with sugar like C<has_table()>.
+
+=head2 Using this Metaclass Trait in Practice
+
+Accessing this new C<table> attribute is quite simple. Given a class
+named C<MyApp::User>, we could simply write the following:
+
+ my $table = MyApp::User->meta->table;
+
+As long as C<MyApp::User> has arranged to apply the
+C<MyApp::Meta::Class::Trait::HasTable> to its metaclass, this method call just
+works. If we want to be more careful, we can check that the class metaclass
+object has a C<table> method:
+
+ $table = MyApp::User->meta->table
+ if MyApp::User->meta->can('table');
+
+In theory, this is not entirely correct, since the metaclass might be getting
+its C<table> method from a I<different> trait. In practice, you are unlikely
+to encounter this sort of problem.
+
+=head1 RECIPE CAVEAT
+
+This recipe doesn't work when you paste it all into a single file. This is
+because the C<< use Moose -traits => 'HasTable'; >> line ends up being
+executed before the C<table> attribute is defined.
+
+When the two packages are separate files, this just works.
+
+=head1 SEE ALSO
+
+L<Moose::Cookbook::Meta::Labeled_AttributeTrait> - Labels implemented via
+attribute traits
+
+=for testing can_ok( MyApp::User->meta, 'table' );
+is( MyApp::User->meta->table, 'User', 'My::User table is User' );
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Stevan Little <stevan.little@iinteractive.com>
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=item *
+
+Shawn M Moore <code@sartak.org>
+
+=item *
+
+יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Florian Ragwitz <rafl@debian.org>
+
+=item *
+
+Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=item *
+
+Chris Prather <chris@prather.org>
+
+=item *
+
+Matt S Trout <mst@shadowcat.co.uk>
+
+=back
+
+=head1 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.
+
+=cut
diff --git a/lib/Moose/Cookbook/Meta/WhyMeta.pod b/lib/Moose/Cookbook/Meta/WhyMeta.pod
new file mode 100644
index 0000000..9ea83f3
--- /dev/null
+++ b/lib/Moose/Cookbook/Meta/WhyMeta.pod
@@ -0,0 +1,117 @@
+# PODNAME: Moose::Cookbook::Meta::WhyMeta
+# ABSTRACT: Welcome to the meta world (Why Go Meta?)
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Moose::Cookbook::Meta::WhyMeta - Welcome to the meta world (Why Go Meta?)
+
+=head1 VERSION
+
+version 2.1405
+
+=head1 SUMMARY
+
+You might want to read L<Moose::Manual::MOP> if you haven't done so
+yet.
+
+If you've ever thought "Moose is great, but I wish it did X
+differently", then you've gone meta. The meta recipes demonstrate how
+to change and extend the way Moose works by extending and overriding
+how the meta classes (L<Moose::Meta::Class>,
+L<Moose::Meta::Attribute>, etc) work.
+
+The metaclass API is a set of classes that describe classes, roles,
+attributes, etc. The metaclass API lets you ask questions about a
+class, like "what attributes does it have?", or "what roles does the
+class do?"
+
+The metaclass system also lets you make changes to a class, for
+example by adding new methods or attributes.
+
+The interface presented by L<Moose.pm|Moose> (C<has>, C<with>,
+C<extends>) is just a thin layer of syntactic sugar over the
+underlying metaclass system.
+
+By extending and changing how this metaclass system works, you can
+create your own Moose variant.
+
+=head2 Examples
+
+Let's say that you want to add additional properties to
+attributes. Specifically, we want to add a "label" property to each
+attribute, so we can write C<<
+My::Class->meta()->get_attribute('size')->label() >>. The first
+recipe shows how to do this using an attribute trait.
+
+You might also want to add additional properties to your
+metaclass. For example, if you were writing an ORM based on Moose, you
+could associate a table name with each class via the class's metaclass
+object, letting you write C<< My::Class->meta()->table_name() >>.
+
+=head1 SEE ALSO
+
+Many of the MooseX modules on CPAN implement metaclass extensions. A
+couple good examples include L<MooseX::Aliases> and
+L<MooseX::UndefTolerant>. For a more complex example see
+L<Fey::ORM> or L<Bread::Board::Declare>.
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Stevan Little <stevan.little@iinteractive.com>
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=item *
+
+Shawn M Moore <code@sartak.org>
+
+=item *
+
+יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Florian Ragwitz <rafl@debian.org>
+
+=item *
+
+Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=item *
+
+Chris Prather <chris@prather.org>
+
+=item *
+
+Matt S Trout <mst@shadowcat.co.uk>
+
+=back
+
+=head1 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.
+
+=cut