This commit is contained in:
397
CPAN/Moose/Spec/Role.pod
Normal file
397
CPAN/Moose/Spec/Role.pod
Normal file
@@ -0,0 +1,397 @@
|
||||
# PODNAME: Moose::Spec::Role
|
||||
# ABSTRACT: Formal spec for Role behavior
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Moose::Spec::Role - Formal spec for Role behavior
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 2.2207
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<NOTE:> This document is currently incomplete.
|
||||
|
||||
=head2 Components of a Role
|
||||
|
||||
=over 4
|
||||
|
||||
=item Excluded Roles
|
||||
|
||||
A role can have a list of excluded roles, these are basically
|
||||
roles that they shouldn't be composed with. This is not just
|
||||
direct composition either, but also "inherited" composition.
|
||||
|
||||
This feature was taken from the Fortress language and is really
|
||||
of most use when building a large set of role "building blocks"
|
||||
some of which should never be used together.
|
||||
|
||||
=item Attributes
|
||||
|
||||
A roles attributes are similar to those of a class, except that
|
||||
they are not actually applied. This means that methods that are
|
||||
generated by an attributes accessor will not be generated in the
|
||||
role, but only created once the role is applied to a class.
|
||||
|
||||
=item Methods
|
||||
|
||||
These are the methods defined within the role. Simple as that.
|
||||
|
||||
=item Required Methods
|
||||
|
||||
A role can require a consuming class (or role) to provide a
|
||||
given method. Failure to do so for classes is a fatal error,
|
||||
while for roles it simply passes on the method requirement to
|
||||
the consuming role.
|
||||
|
||||
=item Required Attributes
|
||||
|
||||
Just as a role can require methods, it can also require attributes.
|
||||
The requirement fulfilling attribute must implement at least as much
|
||||
as is required. That means, for instance, that if the role requires
|
||||
that the attribute be read-only, then it must at least have a reader
|
||||
and can also have a writer. It means that if the role requires that
|
||||
the attribute be an ArrayRef, then it must either be an ArrayRef or
|
||||
a subtype of an ArrayRef.
|
||||
|
||||
=item Overridden Methods
|
||||
|
||||
The C<override> and C<super> keywords are allowed in roles, but
|
||||
their behavior is different from that of its class counterparts.
|
||||
The C<super> in a class refers directly to that class's superclass,
|
||||
while the C<super> in a role is deferred and only has meaning once
|
||||
the role is composed into a class. Once that composition occurs,
|
||||
C<super> then refers to that class's superclass.
|
||||
|
||||
It is key to remember that roles do not have hierarchy, so they
|
||||
can never have a I<super> role.
|
||||
|
||||
=item Method Modifiers
|
||||
|
||||
These are the C<before>, C<around> and C<after> modifiers provided
|
||||
in Moose classes. The difference here is that the modifiers are not
|
||||
actually applied until the role is composed into a class (this is
|
||||
just like attributes and the C<override> keyword).
|
||||
|
||||
=back
|
||||
|
||||
=head2 Role Composition
|
||||
|
||||
=head3 Composing into a Class
|
||||
|
||||
=over 4
|
||||
|
||||
=item Excluded Roles
|
||||
|
||||
=item Required Methods
|
||||
|
||||
=item Required Attributes
|
||||
|
||||
=item Attributes
|
||||
|
||||
=item Methods
|
||||
|
||||
=item Overridden methods
|
||||
|
||||
=item Method Modifiers (before, around, after)
|
||||
|
||||
=back
|
||||
|
||||
=head3 Composing into a Instance
|
||||
|
||||
=head3 Composing into a Role
|
||||
|
||||
=over 4
|
||||
|
||||
=item Excluded Roles
|
||||
|
||||
=item Required Methods
|
||||
|
||||
=item Required Attributes
|
||||
|
||||
=item Attributes
|
||||
|
||||
=item Methods
|
||||
|
||||
=item Overridden methods
|
||||
|
||||
=item Method Modifiers (before, around, after)
|
||||
|
||||
=back
|
||||
|
||||
=head3 Role Summation
|
||||
|
||||
When multiple roles are added to another role (using the
|
||||
C<with @roles> keyword) the roles are composed symmetrically.
|
||||
The product of the composition is a composite role
|
||||
(L<Moose::Meta::Role::Composite>).
|
||||
|
||||
=over 4
|
||||
|
||||
=item Excluded Roles
|
||||
|
||||
=item Required Methods
|
||||
|
||||
=item Required Attributes
|
||||
|
||||
=item Attributes
|
||||
|
||||
Attributes with the same name will conflict and are considered
|
||||
a unrecoverable error. No other aspect of the attribute is
|
||||
examined, it is enough that just the attribute names conflict.
|
||||
|
||||
The reason for such early and harsh conflicts with attributes
|
||||
is because there is so much room for variance between two
|
||||
attributes that the problem quickly explodes and rules get
|
||||
very complex. It is my opinion that this complexity is not
|
||||
worth the trouble.
|
||||
|
||||
=item Methods
|
||||
|
||||
Methods with the same name will conflict, but no error is
|
||||
thrown, instead the method name is added to the list of
|
||||
I<required> methods for the new composite role.
|
||||
|
||||
To look at this in terms of set theory, each role can be
|
||||
said to have a set of methods. The symmetric difference of
|
||||
these two sets is the new set of methods for the composite
|
||||
role, while the intersection of these two sets are the
|
||||
conflicts. This can be illustrated like so:
|
||||
|
||||
Role A has method set { a, b, c }
|
||||
Role B has method set { c, d, e }
|
||||
|
||||
The composite role (A,B) has
|
||||
method set { a, b, d, e }
|
||||
conflict set { c }
|
||||
|
||||
=item Overridden methods
|
||||
|
||||
An overridden method can conflict in one of two ways.
|
||||
|
||||
The first way is with another overridden method of the same
|
||||
name, and this is considered an unrecoverable error. This
|
||||
is an obvious error since you cannot override a method twice
|
||||
in the same class.
|
||||
|
||||
The second way for conflict is for an overridden method and a
|
||||
regular method to have the same name. This is also an unrecoverable
|
||||
error since there is no way to combine these two, nor is it
|
||||
okay for both items to be composed into a single class at some
|
||||
point.
|
||||
|
||||
The use of override in roles can be tricky, but if used
|
||||
carefully they can be a very powerful tool.
|
||||
|
||||
=item Method Modifiers (before, around, after)
|
||||
|
||||
Method modifiers are the only place where the ordering of
|
||||
role composition matters. This is due to the nature of
|
||||
method modifiers themselves.
|
||||
|
||||
Since a method can have multiple method modifiers, these
|
||||
are just collected in order to be later applied to the
|
||||
class in that same order.
|
||||
|
||||
In general, great care should be taken in using method
|
||||
modifiers in roles. The order sensitivity can possibly
|
||||
lead to subtle and difficult to find bugs if they are
|
||||
overused. As with all good things in life, moderation
|
||||
is the key.
|
||||
|
||||
=back
|
||||
|
||||
=head3 Composition Edge Cases
|
||||
|
||||
This is a just a set of complex edge cases which can easily get
|
||||
confused. This attempts to clarify those cases and provide an
|
||||
explanation of what is going on in them.
|
||||
|
||||
=over 4
|
||||
|
||||
=item Role Method Overriding
|
||||
|
||||
Many people want to "override" methods in roles they are consuming.
|
||||
This works fine for classes, since the local class method is favored
|
||||
over the role method. However in roles it is trickier, this is because
|
||||
conflicts result in neither method being chosen and the method being
|
||||
"required" instead.
|
||||
|
||||
Here is an example of this (incorrect) type of overriding.
|
||||
|
||||
package Role::Foo;
|
||||
use Moose::Role;
|
||||
|
||||
sub foo { ... }
|
||||
|
||||
package Role::FooBar;
|
||||
use Moose::Role;
|
||||
|
||||
with 'Role::Foo';
|
||||
|
||||
sub foo { ... }
|
||||
sub bar { ... }
|
||||
|
||||
Here the C<foo> methods conflict and the Role::FooBar now requires a
|
||||
class or role consuming it to implement C<foo>. This is very often not
|
||||
what the user wants.
|
||||
|
||||
Now here is an example of the (correct) type of overriding, only it is
|
||||
not overriding at all, as is explained in the text below.
|
||||
|
||||
package Role::Foo;
|
||||
use Moose::Role;
|
||||
|
||||
sub foo { ... }
|
||||
|
||||
package Role::Bar;
|
||||
use Moose::Role;
|
||||
|
||||
sub foo { ... }
|
||||
sub bar { ... }
|
||||
|
||||
package Role::FooBar;
|
||||
use Moose::Role;
|
||||
|
||||
with 'Role::Foo', 'Role::Bar';
|
||||
|
||||
sub foo { ... }
|
||||
|
||||
This works because the combination of Role::Foo and Role::Bar produce
|
||||
a conflict with the C<foo> method. This conflict results in the
|
||||
composite role (that was created by the combination of Role::Foo
|
||||
and Role::Bar using the I<with> keyword) having a method requirement
|
||||
of C<foo>. The Role::FooBar then fulfills this requirement.
|
||||
|
||||
It is important to note that Role::FooBar is simply fulfilling the
|
||||
required C<foo> method, and **NOT** overriding C<foo>. This is an
|
||||
important distinction to make.
|
||||
|
||||
Now here is another example of a (correct) type of overriding, this
|
||||
time using the I<excludes> option.
|
||||
|
||||
package Role::Foo;
|
||||
use Moose::Role;
|
||||
|
||||
sub foo { ... }
|
||||
|
||||
package Role::FooBar;
|
||||
use Moose::Role;
|
||||
|
||||
with 'Role::Foo' => { -excludes => 'foo' };
|
||||
|
||||
sub foo { ... }
|
||||
sub bar { ... }
|
||||
|
||||
By specifically excluding the C<foo> method during composition,
|
||||
we allow B<Role::FooBar> to define its own version of C<foo>.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item Traits
|
||||
|
||||
Roles are based on Traits, which originated in the Smalltalk
|
||||
community.
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.iam.unibe.ch/~scg/Research/Traits/>
|
||||
|
||||
This is the main site for the original Traits papers.
|
||||
|
||||
=item L<Class::Trait>
|
||||
|
||||
I created this implementation of traits several years ago,
|
||||
after reading the papers linked above. (This module is now
|
||||
maintained by Ovid and I am no longer involved with it).
|
||||
|
||||
=back
|
||||
|
||||
=item Roles
|
||||
|
||||
Since they are relatively new, and the Moose implementation
|
||||
is probably the most mature out there, roles don't have much
|
||||
to link to. However, here is some bits worth looking at (mostly
|
||||
related to Perl 6)
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.oreillynet.com/onlamp/blog/2006/08/roles_composable_units_of_obje.html>
|
||||
|
||||
This is chromatic's take on roles, which is worth reading since
|
||||
he was/is one of the big proponents of them.
|
||||
|
||||
=item L<http://svn.perl.org/perl6/doc/trunk/design/syn/S12.pod>
|
||||
|
||||
This is Synopsis 12, which is all about the Perl 6 Object System.
|
||||
Which, of course, includes roles.
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
Stevan Little <stevan@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Dave Rolsky <autarch@urth.org>
|
||||
|
||||
=item *
|
||||
|
||||
Jesse Luehrs <doy@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Shawn M Moore <sartak@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
|
||||
|
||||
=item *
|
||||
|
||||
Karen Etheridge <ether@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Florian Ragwitz <rafl@debian.org>
|
||||
|
||||
=item *
|
||||
|
||||
Hans Dieter Pearcey <hdp@cpan.org>
|
||||
|
||||
=item *
|
||||
|
||||
Chris Prather <chris@prather.org>
|
||||
|
||||
=item *
|
||||
|
||||
Matt S Trout <mstrout@cpan.org>
|
||||
|
||||
=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
|
||||
Reference in New Issue
Block a user