X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose.pm;h=4edb87c89be60d348c2cc93a4d99290165c9baa0;hb=c78749468bd025340411de01eabcc74116216ed8;hp=a72df14475ca7dc39cb16206e43e7802a2f28d1b;hpb=c8cf9aaaa9bc89f8a889c3c17d163034dc59a410;p=gitmo%2FMoose.git diff --git a/lib/Moose.pm b/lib/Moose.pm index a72df14..4edb87c 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -4,16 +4,18 @@ package Moose; use strict; use warnings; -our $VERSION = '0.16'; +use 5.008; -use Scalar::Util 'blessed', 'reftype'; -use Carp 'confess'; -use Sub::Name 'subname'; -use B 'svref_2object'; +our $VERSION = '0.60'; +$VERSION = eval $VERSION; +our $AUTHORITY = 'cpan:STEVAN'; -use Sub::Exporter; +use Scalar::Util 'blessed'; +use Carp 'confess', 'croak', 'cluck'; -use Class::MOP; +use Moose::Exporter; + +use Class::MOP 0.68; use Moose::Meta::Class; use Moose::Meta::TypeConstraint; @@ -22,229 +24,267 @@ use Moose::Meta::Attribute; use Moose::Meta::Instance; use Moose::Object; + +use Moose::Meta::Role; +use Moose::Meta::Role::Composite; +use Moose::Meta::Role::Application; +use Moose::Meta::Role::Application::RoleSummation; +use Moose::Meta::Role::Application::ToClass; +use Moose::Meta::Role::Application::ToRole; +use Moose::Meta::Role::Application::ToInstance; + use Moose::Util::TypeConstraints; +use Moose::Util (); + +sub throw_error { + # FIXME This + shift; + goto \&confess +} + +sub extends { + my $class = shift; + + croak "Must derive at least one class" unless @_; + + my @supers = @_; + foreach my $super (@supers) { + Class::MOP::load_class($super); + croak "You cannot inherit from a Moose Role ($super)" + if $super->can('meta') && + blessed $super->meta && + $super->meta->isa('Moose::Meta::Role') + } + + + + # this checks the metaclass to make sure + # it is correct, sometimes it can get out + # of sync when the classes are being built + my $meta = Moose::Meta::Class->initialize($class); + $meta->superclasses(@supers); +} + +sub with { + my $class = shift; + Moose::Util::apply_all_roles(Class::MOP::Class->initialize($class), @_); +} + +sub has { + my $class = shift; + my $name = shift; + croak 'Usage: has \'name\' => ( key => value, ... )' if @_ == 1; + my %options = @_; + my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ]; + Class::MOP::Class->initialize($class)->add_attribute( $_, %options ) for @$attrs; +} + +sub before { + my $class = shift; + Moose::Util::add_method_modifier($class, 'before', \@_); +} + +sub after { + my $class = shift; + Moose::Util::add_method_modifier($class, 'after', \@_); +} + +sub around { + my $class = shift; + Moose::Util::add_method_modifier($class, 'around', \@_); +} + +sub super { + return unless our $SUPER_BODY; $SUPER_BODY->(our @SUPER_ARGS); +} + +sub override { + my $class = shift; + my ( $name, $method ) = @_; + Class::MOP::Class->initialize($class)->add_override_method_modifier( $name => $method ); +} + +sub inner { + my $pkg = caller(); + our ( %INNER_BODY, %INNER_ARGS ); + + if ( my $body = $INNER_BODY{$pkg} ) { + my @args = @{ $INNER_ARGS{$pkg} }; + local $INNER_ARGS{$pkg}; + local $INNER_BODY{$pkg}; + return $body->(@args); + } else { + return; + } +} -{ - my $CALLER; +sub augment { + my $class = shift; + my ( $name, $method ) = @_; + Class::MOP::Class->initialize($class)->add_augment_method_modifier( $name => $method ); +} + +sub make_immutable { + my $class = shift; + cluck "The make_immutable keyword has been deprecated, " . + "please go back to __PACKAGE__->meta->make_immutable\n"; + Class::MOP::Class->initialize($class)->make_immutable(@_); +} + +Moose::Exporter->setup_import_methods( + with_caller => [ + qw( extends with has before after around override augment make_immutable ) + ], + as_is => [ + qw( super inner ), + \&Carp::confess, + \&Scalar::Util::blessed, + ], +); + +sub init_meta { + # This used to be called as a function. This hack preserves + # backwards compatibility. + if ( $_[0] ne __PACKAGE__ ) { + return __PACKAGE__->init_meta( + for_class => $_[0], + base_class => $_[1], + metaclass => $_[2], + ); + } + + shift; + my %args = @_; - sub _init_meta { - my $class = $CALLER; + my $class = $args{for_class} + or Moose->throw_error("Cannot call init_meta without specifying a for_class"); + my $base_class = $args{base_class} || 'Moose::Object'; + my $metaclass = $args{metaclass} || 'Moose::Meta::Class'; - # make a subtype for each Moose class - subtype $class - => as 'Object' - => where { $_->isa($class) } - => optimize_as { blessed($_[0]) && $_[0]->isa($class) } + Moose->throw_error("The Metaclass $metaclass must be a subclass of Moose::Meta::Class.") + unless $metaclass->isa('Moose::Meta::Class'); + + # make a subtype for each Moose class + class_type($class) unless find_type_constraint($class); - my $meta; - if ($class->can('meta')) { - # NOTE: - # this is the case where the metaclass pragma - # was used before the 'use Moose' statement to - # override a specific class - $meta = $class->meta(); - (blessed($meta) && $meta->isa('Moose::Meta::Class')) - || confess "You already have a &meta function, but it does not return a Moose::Meta::Class"; + my $meta; + + if ( $meta = Class::MOP::get_metaclass_by_name($class) ) { + unless ( $meta->isa("Moose::Meta::Class") ) { + Moose->throw_error("$class already has a metaclass, but it does not inherit $metaclass ($meta)"); } - else { - # NOTE: - # this is broken currently, we actually need - # to allow the possiblity of an inherited - # meta, which will not be visible until the - # user 'extends' first. This needs to have - # more intelligence to it - $meta = Moose::Meta::Class->initialize($class); - $meta->add_method('meta' => sub { - # re-initialize so it inherits properly - Moose::Meta::Class->initialize(blessed($_[0]) || $_[0]); - }) + } else { + # no metaclass, no 'meta' method + + # now we check whether our ancestors have metaclass, and if so borrow that + my ( undef, @isa ) = @{ $class->mro::get_linear_isa }; + + foreach my $ancestor ( @isa ) { + my $ancestor_meta = Class::MOP::get_metaclass_by_name($ancestor) || next; + + my $ancestor_meta_class = ($ancestor_meta->is_immutable + ? $ancestor_meta->get_mutable_metaclass_name + : ref($ancestor_meta)); + + # if we have an ancestor metaclass that inherits $metaclass, we use + # that. This is like _fix_metaclass_incompatibility, but we can do it now. + + # the case of having an ancestry is not very common, but arises in + # e.g. Reaction + unless ( $metaclass->isa( $ancestor_meta_class ) ) { + if ( $ancestor_meta_class->isa($metaclass) ) { + $metaclass = $ancestor_meta_class; + } + } } - # make sure they inherit from Moose::Object - $meta->superclasses('Moose::Object') - unless $meta->superclasses(); + $meta = $metaclass->initialize($class); } - my %exports = ( - extends => sub { - my $class = $CALLER; - return subname 'Moose::extends' => sub (@) { - confess "Must derive at least one class" unless @_; - _load_all_classes(@_); - # this checks the metaclass to make sure - # it is correct, sometimes it can get out - # of sync when the classes are being built - my $meta = $class->meta->_fix_metaclass_incompatability(@_); - $meta->superclasses(@_); - }; - }, - with => sub { - my $class = $CALLER; - return subname 'Moose::with' => sub (@) { - my (@roles) = @_; - confess "Must specify at least one role" unless @roles; - _load_all_classes(@roles); - $class->meta->_apply_all_roles(@roles); - }; - }, - has => sub { - my $class = $CALLER; - return subname 'Moose::has' => sub ($;%) { - my ($name, %options) = @_; - $class->meta->_process_attribute($name, %options); - }; - }, - before => sub { - my $class = $CALLER; - return subname 'Moose::before' => sub (@&) { - my $code = pop @_; - my $meta = $class->meta; - $meta->add_before_method_modifier($_, $code) for @_; - }; - }, - after => sub { - my $class = $CALLER; - return subname 'Moose::after' => sub (@&) { - my $code = pop @_; - my $meta = $class->meta; - $meta->add_after_method_modifier($_, $code) for @_; - }; - }, - around => sub { - my $class = $CALLER; - return subname 'Moose::around' => sub (@&) { - my $code = pop @_; - my $meta = $class->meta; - $meta->add_around_method_modifier($_, $code) for @_; - }; - }, - super => sub { - return subname 'Moose::super' => sub {}; - }, - override => sub { - my $class = $CALLER; - return subname 'Moose::override' => sub ($&) { - my ($name, $method) = @_; - $class->meta->add_override_method_modifier($name => $method); - }; - }, - inner => sub { - return subname 'Moose::inner' => sub {}; - }, - augment => sub { - my $class = $CALLER; - return subname 'Moose::augment' => sub (@&) { - my ($name, $method) = @_; - $class->meta->add_augment_method_modifier($name => $method); - }; - }, - + if ( $class->can('meta') ) { + # check 'meta' method + + # it may be inherited + # NOTE: - # this is experimental, but I am not - # happy with it. If you want to try - # it, you will have to uncomment it - # yourself. - # There is a really good chance that - # this will be deprecated, dont get - # too attached - # self => sub { - # return subname 'Moose::self' => sub {}; - # }, - # method => sub { - # my $class = $CALLER; - # return subname 'Moose::method' => sub { - # my ($name, $method) = @_; - # $class->meta->add_method($name, sub { - # my $self = shift; - # no strict 'refs'; - # no warnings 'redefine'; - # local *{$class->meta->name . '::self'} = sub { $self }; - # $method->(@_); - # }); - # }; - # }, - - confess => sub { - return \&Carp::confess; - }, - blessed => sub { - return \&Scalar::Util::blessed; - }, - ); - - my $exporter = Sub::Exporter::build_exporter({ - exports => \%exports, - groups => { - default => [':all'] - } - }); - - sub import { - $CALLER = caller(); - - strict->import; - warnings->import; - - # we should never export to main - return if $CALLER eq 'main'; - - _init_meta(); - - goto $exporter; + # this is the case where the metaclass pragma + # was used before the 'use Moose' statement to + # override a specific class + my $method_meta = $class->meta; + + ( blessed($method_meta) && $method_meta->isa('Moose::Meta::Class') ) + || Moose->throw_error("$class already has a &meta function, but it does not return a Moose::Meta::Class ($meta)"); + + $meta = $method_meta; } - - sub unimport { - no strict 'refs'; - my $class = caller(); - # loop through the exports ... - foreach my $name (keys %exports) { - next if $name =~ /inner|super|self/; - - # if we find one ... - if (defined &{$class . '::' . $name}) { - my $keyword = \&{$class . '::' . $name}; - - # make sure it is from Moose - my $pkg_name = eval { svref_2object($keyword)->GV->STASH->NAME }; - next if $@; - next if $pkg_name ne 'Moose'; - - # and if it is from Moose then undef the slot - delete ${$class . '::'}{$name}; + + unless ( $meta->has_method("meta") ) { # don't overwrite + # also check for inherited non moose 'meta' method? + # FIXME also skip this if the user requested by passing an option + $meta->add_method( + 'meta' => sub { + # re-initialize so it inherits properly + $metaclass->initialize( ref($_[0]) || $_[0] ); } - } + ); } -} -## Utility functions - -sub _load_all_classes { - foreach my $class (@_) { - # see if this is already - # loaded in the symbol table - next if _is_class_already_loaded($class); - # otherwise require it ... - my $file = $class . '.pm'; - $file =~ s{::}{/}g; - eval { CORE::require($file) }; - confess( - "Could not load module '$class' because : $@" - ) if $@; - } + # make sure they inherit from Moose::Object + $meta->superclasses($base_class) + unless $meta->superclasses(); + + return $meta; } -sub _is_class_already_loaded { - my $name = shift; - no strict 'refs'; - return 1 if defined ${"${name}::VERSION"} || defined @{"${name}::ISA"}; - foreach (keys %{"${name}::"}) { - next if substr($_, -2, 2) eq '::'; - return 1 if defined &{"${name}::$_"}; - } - return 0; +# This may be used in some older MooseX extensions. +sub _get_caller { + goto &Moose::Exporter::_get_caller; } +## make 'em all immutable + +$_->meta->make_immutable( + inline_constructor => 1, + constructor_name => "_new", + inline_accessors => 1, # these are Class::MOP accessors, so they need inlining + ) + for (qw( + Moose::Meta::Attribute + Moose::Meta::Class + Moose::Meta::Instance + + Moose::Meta::TypeConstraint + Moose::Meta::TypeConstraint::Union + Moose::Meta::TypeConstraint::Parameterized + Moose::Meta::TypeConstraint::Parameterizable + Moose::Meta::TypeConstraint::Enum + Moose::Meta::TypeConstraint::Class + Moose::Meta::TypeConstraint::Role + Moose::Meta::TypeConstraint::Registry + Moose::Meta::TypeCoercion + Moose::Meta::TypeCoercion::Union + + Moose::Meta::Method + Moose::Meta::Method::Accessor + Moose::Meta::Method::Constructor + Moose::Meta::Method::Destructor + Moose::Meta::Method::Overriden + Moose::Meta::Method::Augmented + + Moose::Meta::Role + Moose::Meta::Role::Method + Moose::Meta::Role::Method::Required + + Moose::Meta::Role::Composite + + Moose::Meta::Role::Application + Moose::Meta::Role::Application::RoleSummation + Moose::Meta::Role::Application::ToClass + Moose::Meta::Role::Application::ToRole + Moose::Meta::Role::Application::ToInstance +)); + 1; __END__ @@ -253,80 +293,65 @@ __END__ =head1 NAME -Moose - A complete modern object system for Perl 5 +Moose - A postmodern object system for Perl 5 =head1 SYNOPSIS package Point; - use strict; - use warnings; - use Moose; - + use Moose; # automatically turns on strict and warnings + has 'x' => (is => 'rw', isa => 'Int'); has 'y' => (is => 'rw', isa => 'Int'); - + sub clear { my $self = shift; $self->x(0); - $self->y(0); + $self->y(0); } - + package Point3D; - use strict; - use warnings; use Moose; - + extends 'Point'; - + has 'z' => (is => 'rw', isa => 'Int'); - + after 'clear' => sub { my $self = shift; $self->z(0); }; - -=head1 CAVEAT - -Moose is a rapidly maturing module, and is already being used by -a number of people. It's test suite is growing larger by the day, -and the docs should soon follow. - -This said, Moose is not yet finished, and should still be considered -to be evolving. Much of the outer API is stable, but the internals -are still subject to change (although not without serious thought -given to it). =head1 DESCRIPTION -Moose is an extension of the Perl 5 object system. +Moose is an extension of the Perl 5 object system. -=head2 Another object system!?!? +The main goal of Moose is to make Perl 5 Object Oriented programming +easier, more consistent and less tedious. With Moose you can to think +more about what you want to do and less about the mechanics of OOP. -Yes, I know there has been an explosion recently of new ways to -build object's in Perl 5, most of them based on inside-out objects -and other such things. Moose is different because it is not a new -object system for Perl 5, but instead an extension of the existing -object system. +Additionally, Moose is built on top of L, which is a +metaclass system for Perl 5. This means that Moose not only makes +building normal Perl 5 objects better, but it provides the power of +metaclass programming as well. -Moose is built on top of L, which is a metaclass system -for Perl 5. This means that Moose not only makes building normal -Perl 5 objects better, but it also provides the power of metaclass -programming. +=head2 New to Moose? -=head2 Can I use this in production? Or is this just an experiment? +If you're new to Moose, the best place to start is the L +docs, followed by the L. The intro will show you what +Moose is, and how it makes Perl 5 OO better. -Moose is I on the prototypes and experiments I did for the Perl 6 -meta-model; however Moose is B an experiment/prototype, it is -for B. I will be deploying Moose into production environments later -this year, and I have every intentions of using it as my de facto class -builder from now on. +The cookbook recipes on Moose basics will get you up to speed with +many of Moose's features quickly. Once you have an idea of what Moose +can do, you can use the API documentation to get more detail on +features which interest you. -=head2 Is Moose just Perl 6 in Perl 5? +=head2 Moose Extensions -No. While Moose is very much inspired by Perl 6, it is not itself Perl 6. -Instead, it is an OO system for Perl 5. I built Moose because I was tired or -writing the same old boring Perl 5 OO code, and drooling over Perl 6 OO. So -instead of switching to Ruby, I wrote Moose :) +The C namespace is the official place to find Moose extensions. +These extensions can be found on the CPAN. The easiest way to find them +is to search for them (L), +or to examine L which aims to keep an up-to-date, easily +installable list of Moose extensions. =head1 BUILDING CLASSES WITH MOOSE @@ -334,20 +359,19 @@ Moose makes every attempt to provide as much convenience as possible during class construction/definition, but still stay out of your way if you want it to. Here are a few items to note when building classes with Moose. -Unless specified with C, any class which uses Moose will +Unless specified with C, any class which uses Moose will inherit from L. -Moose will also manage all attributes (including inherited ones) that -are defined with C. And assuming that you call C, which is -inherited from L, then this includes properly initializing -all instance slots, setting defaults where appropriate, and performing any -type constraint checking or coercion. +Moose will also manage all attributes (including inherited ones) that are +defined with C. And (assuming you call C, which is inherited from +L) this includes properly initializing all instance slots, +setting defaults where appropriate, and performing any type constraint checking +or coercion. -=head1 EXPORTED FUNCTIONS +=head1 PROVIDED METHODS -Moose will export a number of functions into the class's namespace which -can then be used to set up the class. These functions all work directly -on the current class. +Moose provides a number of methods to all your classes, mostly through the +inheritance of L. There is however, one exception. =over 4 @@ -355,63 +379,78 @@ on the current class. This is a method which provides access to the current class's metaclass. +=back + +=head1 EXPORTED FUNCTIONS + +Moose will export a number of functions into the class's namespace which +may then be used to set up the class. These functions all work directly +on the current class. + +=over 4 + =item B This function will set the superclass(es) for the current class. -This approach is recommended instead of C, because C -actually Ces onto the class's C<@ISA>, whereas C will -replace it. This is important to ensure that classes which do not have +This approach is recommended instead of C, because C +actually Ces onto the class's C<@ISA>, whereas C will +replace it. This is important to ensure that classes which do not have superclasses still properly inherit from L. =item B -This will apply a given set of C<@roles> to the local class. Role support -is currently under heavy development; see L for more details. +This will apply a given set of C<@roles> to the local class. -=item B +=item B %options> -This will install an attribute of a given C<$name> into the current class. -The list of C<%options> are the same as those provided by -L, in addition to the list below which are provided -by Moose (L to be more specific): +This will install an attribute of a given C<$name> into the current class. If +the first parameter is an array reference, it will create an attribute for +every C<$name> in the list. The C<%options> are the same as those provided by +L, in addition to the list below which are provided by +Moose (L to be more specific): =over 4 =item I 'rw'|'ro'> -The I option accepts either I (for read/write) or I (for read -only). These will create either a read/write accessor or a read-only +The I option accepts either I (for read/write) or I (for read +only). These will create either a read/write accessor or a read-only accessor respectively, using the same name as the C<$name> of the attribute. -If you need more control over how your accessors are named, you can use the -I, I and I options inherited from L. +If you need more control over how your accessors are named, you can +use the L, +L and +L options inherited from +L, however if you use those, you won't need the +I option. =item I $type_name> -The I option uses Moose's type constraint facilities to set up runtime -type checking for this attribute. Moose will perform the checks during class -construction, and within any accessors. The C<$type_name> argument must be a -string. The string can be either a class name or a type defined using -Moose's type definition features. +The I option uses Moose's type constraint facilities to set up runtime +type checking for this attribute. Moose will perform the checks during class +construction, and within any accessors. The C<$type_name> argument must be a +string. The string may be either a class name or a type defined using +Moose's type definition features. (Refer to L +for information on how to define a new type, and how to retrieve type meta-data). =item I (1|0)> -This will attempt to use coercion with the supplied type constraint to change -the value passed into any accessors or constructors. You B have supplied -a type constraint in order for this to work. See L -for an example usage. +This will attempt to use coercion with the supplied type constraint to change +the value passed into any accessors or constructors. You B have supplied +a type constraint in order for this to work. See L +for an example. =item I $role_name> -This will accept the name of a role which the value stored in this attribute +This will accept the name of a role which the value stored in this attribute is expected to have consumed. =item I (1|0)> -This marks the attribute as being required. This means a value must be supplied -during class construction, and the attribute can never be set to C with -an accessor. +This marks the attribute as being required. This means a I value must be +supplied during class construction, and the attribute may never be set to +C with an accessor. =item I (1|0)> @@ -421,26 +460,305 @@ coerced. =item I (1|0)> -This will tell the class to not create this slot until absolutely necessary. +This will tell the class to not create this slot until absolutely necessary. If an attribute is marked as lazy it B have a default supplied. =item I (1|0)> -This tells the accessor whether to automatically dereference the value returned. -This is only legal if your C option is either an C or C. +This tells the accessor whether to automatically dereference the value returned. +This is only legal if your C option is either C or C. =item I $code> -The trigger option is a CODE reference which will be called after the value of -the attribute is set. The CODE ref will be passed the instance itself, the +The I option is a CODE reference which will be called after the value of +the attribute is set. The CODE ref will be passed the instance itself, the updated value and the attribute meta-object (this is for more advanced fiddling -and can typically be ignored in most cases). You B have a trigger on -a read-only attribute. +and can typically be ignored). You B have a trigger on a read-only +attribute. + +B Triggers will only fire when you B to the attribute, +either in the constructor, or using the writer. Default and built values will +B cause the trigger to be fired. + +=item I ARRAY | HASH | REGEXP | ROLE | CODE> + +The I option provides Moose classes with automated delegation features. +This is a pretty complex and powerful option. It accepts many different option +formats, each with its own benefits and drawbacks. + +B The class being delegated to does not need to be a Moose based class, +which is why this feature is especially useful when wrapping non-Moose classes. + +All I option formats share the following traits: + +You cannot override a locally defined method with a delegated method; an +exception will be thrown if you try. That is to say, if you define C in +your class, you cannot override it with a delegated C. This is almost never +something you would want to do, and if it is, you should do it by hand and not +use Moose. + +You cannot override any of the methods found in Moose::Object, or the C +and C methods. These will not throw an exception, but will silently +move on to the next method in the list. My reasoning for this is that you would +almost never want to do this, since it usually breaks your class. As with +overriding locally defined methods, if you do want to do this, you should do it +manually, not with Moose. + +You do not I to have a reader (or accessor) for the attribute in order +to delegate to it. Moose will create a means of accessing the value for you, +however this will be several times B efficient then if you had given +the attribute a reader (or accessor) to use. + +Below is the documentation for each option format: + +=over 4 + +=item C + +This is the most common usage for I. You basically pass a list of +method names to be delegated, and Moose will install a delegation method +for each one. + +=item C + +This is the second most common usage for I. Instead of a list of +method names, you pass a HASH ref where each key is the method name you +want installed locally, and its value is the name of the original method +in the class being delegated to. + +This can be very useful for recursive classes like trees. Here is a +quick example (soon to be expanded into a Moose::Cookbook recipe): + + package Tree; + use Moose; + + has 'node' => (is => 'rw', isa => 'Any'); + + has 'children' => ( + is => 'ro', + isa => 'ArrayRef', + default => sub { [] } + ); + + has 'parent' => ( + is => 'rw', + isa => 'Tree', + weak_ref => 1, + handles => { + parent_node => 'node', + siblings => 'children', + } + ); + +In this example, the Tree package gets C and C methods, +which delegate to the C and C methods (respectively) of the Tree +instance stored in the C slot. + +=item C + +The regexp option works very similar to the ARRAY option, except that it builds +the list of methods for you. It starts by collecting all possible methods of the +class being delegated to, then filters that list using the regexp supplied here. + +B An I option is required when using the regexp option format. This +is so that we can determine (at compile time) the method list from the class. +Without an I this is just not possible. + +=item C + +With the role option, you specify the name of a role whose "interface" then +becomes the list of methods to handle. The "interface" can be defined as; the +methods of the role and any required methods of the role. It should be noted +that this does B include any method modifiers or generated attribute +methods (which is consistent with role composition). + +=item C + +This is the option to use when you really want to do something funky. You should +only use it if you really know what you are doing, as it involves manual +metaclass twiddling. + +This takes a code reference, which should expect two arguments. The first is the +attribute meta-object this I is attached to. The second is the +metaclass of the class being delegated to. It expects you to return a hash (not +a HASH ref) of the methods you want mapped. + +=back + +=item I $metaclass_name> + +This tells the class to use a custom attribute metaclass for this particular +attribute. Custom attribute metaclasses are useful for extending the +capabilities of the I keyword: they are the simplest way to extend the MOP, +but they are still a fairly advanced topic and too much to cover here, see +L for more information. + +The default behavior here is to just load C<$metaclass_name>; however, we also +have a way to alias to a shorter name. This will first look to see if +B exists. If it does, Moose +will then check to see if that has the method C, which +should return the actual name of the custom attribute metaclass. If there is no +C method, it will fall back to using +B as the metaclass name. + +=item I [ @role_names ]> + +This tells Moose to take the list of C<@role_names> and apply them to the +attribute meta-object. This is very similar to the I option, but +allows you to use more than one extension at a time. + +See L for details on how a trait name is +resolved to a class name. + +Also see L for a metaclass trait +example. + +=item I + +The value of this key is the name of the method that will be called to +obtain the value used to initialize the attribute. See the L +for more information. + +=item I + +The value of this key is the default value which will initialize the attribute. -=item I [ @handles ]> +NOTE: If the value is a simple scalar (string or number), then it can +be just passed as is. However, if you wish to initialize it with a +HASH or ARRAY ref, then you need to wrap that inside a CODE reference. +See the L for more +information. -There is experimental support for attribute delegation using the C -option. More docs to come later. +=item I + +This may be a method name (referring to a method on the class with +this attribute) or a CODE ref. The initializer is used to set the +attribute value on an instance when the attribute is set during +instance initialization (but not when the value is being assigned +to). See the L for more +information. + +=item I + +Allows you to clear the value, see the L for more +information. + +=item I + +Basic test to see if a value has been set in the attribute, see the +L for more +information. + +=back + +=item B %options> + +This is variation on the normal attribute creator C which allows you to +clone and extend an attribute from a superclass or from a role. Here is an +example of the superclass usage: + + package Foo; + use Moose; + + has 'message' => ( + is => 'rw', + isa => 'Str', + default => 'Hello, I am a Foo' + ); + + package My::Foo; + use Moose; + + extends 'Foo'; + + has '+message' => (default => 'Hello I am My::Foo'); + +What is happening here is that B is cloning the C attribute +from its parent class B, retaining the C 'rw'> and C +'Str'> characteristics, but changing the value in C. + +Here is another example, but within the context of a role: + + package Foo::Role; + use Moose::Role; + + has 'message' => ( + is => 'rw', + isa => 'Str', + default => 'Hello, I am a Foo' + ); + + package My::Foo; + use Moose; + + with 'Foo::Role'; + + has '+message' => (default => 'Hello I am My::Foo'); + +In this case, we are basically taking the attribute which the role supplied +and altering it within the bounds of this feature. + +Aside from where the attributes come from (one from superclass, the other +from a role), this feature works exactly the same. This feature is restricted +somewhat, so as to try and force at least I sanity into it. You are only +allowed to change the following attributes: + +=over 4 + +=item I + +Change the default value of an attribute. + +=item I + +Change whether the attribute attempts to coerce a value passed to it. + +=item I + +Change if the attribute is required to have a value. + +=item I + +Change the documentation string associated with the attribute. + +=item I + +Change if the attribute lazily initializes the slot. + +=item I + +You I allowed to change the type without restriction. + +It is recommended that you use this freedom with caution. We used to +only allow for extension only if the type was a subtype of the parent's +type, but we felt that was too restrictive and is better left as a +policy decision. + +=item I + +You are allowed to B a new C definition, but you are B +allowed to I one. + +=item I + +You are allowed to B a new C definition, but you are B +allowed to I one. + +=item I + +You are allowed to B a new C definition, but you are +B allowed to I one. + +=item I + +You are allowed to B additional traits to the C definition. +These traits will be composed into the attribute, but pre-existing traits +B overridden, or removed. =back @@ -450,54 +768,85 @@ option. More docs to come later. =item B sub { ... }> -This three items are syntactic sugar for the before, after, and around method -modifier features that L provides. More information on these can -be found in the L documentation for now. +This three items are syntactic sugar for the before, after, and around method +modifier features that L provides. More information on these may be +found in the L for now. =item B -The keyword C is a no-op when called outside of an C method. In -the context of an C method, it will call the next most appropriate +The keyword C is a no-op when called outside of an C method. In +the context of an C method, it will call the next most appropriate superclass method with the same arguments as the original method. =item B -An C method is a way of explicitly saying "I am overriding this -method from my superclass". You can call C within this method, and -it will work as expected. The same thing I be accomplished with a normal -method call and the C pseudo-package; it is really your choice. +An C method is a way of explicitly saying "I am overriding this +method from my superclass". You can call C within this method, and +it will work as expected. The same thing I be accomplished with a normal +method call and the C pseudo-package; it is really your choice. =item B -The keyword C, much like C, is a no-op outside of the context of -an C method. You can think of C as being the inverse of +The keyword C, much like C, is a no-op outside of the context of +an C method. You can think of C as being the inverse of C; the details of how C and C work is best described in -the L. +the L. =item B -An C method, is a way of explicitly saying "I am augmenting this -method from my superclass". Once again, the details of how C and -C work is best described in the L. +An C method, is a way of explicitly saying "I am augmenting this +method from my superclass". Once again, the details of how C and +C work is best described in the L. =item B This is the C function, and exported here because I use it -all the time. This feature may change in the future, so you have been warned. +all the time. =item B -This is the C function, it is exported here because I -use it all the time. It is highly recommended that this is used instead of +This is the C function, it is exported here because I +use it all the time. It is highly recommended that this is used instead of C anywhere you need to test for an object's class name. =back -=head1 UNEXPORTING FUNCTIONS +=head1 METACLASS TRAITS + +When you use Moose, you can also specify traits which will be applied +to your metaclass: + + use Moose -traits => 'My::Trait'; + +This is very similar to the attribute traits feature. When you do +this, your class's C object will have the specified traits +applied to it. See L for more details. + +=head1 TRAIT NAME RESOLUTION + +By default, when given a trait name, Moose simply tries to load a +class of the same name. If such a class does not exist, it then looks +for for a class matching +B. The C<$type> +variable here will be one of B or B, depending on +what the trait is being applied to. + +If a class with this long name exists, Moose checks to see if it has +the method C. This method is expected to +return the I class name of the trait. If there is no +C method, it will fall back to using +B as the trait name. + +If all this is confusing, take a look at +L, which demonstrates how to create an +attribute trait. + +=head1 UNIMPORTING FUNCTIONS =head2 B -Moose offers a way of removing the keywords it exports though the C +Moose offers a way to remove the keywords it exports, through the C method. You simply have to say C at the bottom of your code for this to work. Here is an example: @@ -506,39 +855,99 @@ to work. Here is an example: has 'first_name' => (is => 'rw', isa => 'Str'); has 'last_name' => (is => 'rw', isa => 'Str'); - - sub full_name { + + sub full_name { my $self = shift; - $self->first_name . ' ' . $self->last_name + $self->first_name . ' ' . $self->last_name } - - no Moose; # keywords are removed from the Person package -=head1 MISC. + no Moose; # keywords are removed from the Person package -=head2 What does Moose stand for?? +=head1 EXTENDING AND EMBEDDING MOOSE -Moose doesn't stand for one thing in particular, however, if you -want, here are a few of my favorites; feel free to contribute -more :) +To learn more about extending Moose, we recommend checking out the +"Extending" recipes in the L, starting with +L, which provides an overview of +all the different ways you might extend Moose. -=over 4 +=head2 B<< Moose->init_meta(for_class => $class, base_class => $baseclass, metaclass => $metaclass) >> -=item Make Other Object Systems Envious +The C method sets up the metaclass object for the class +specified by C. This method injects a a C accessor +into the class so you can get at this object. It also sets the class's +superclass to C, with L as the default. -=item Makes Object Orientation So Easy +You can specify an alternate metaclass with the C parameter. -=item Makes Object Orientation Spiffy- Er (sorry ingy) +For more detail on this topic, see L. -=item Most Other Object Systems Emasculate +This method used to be documented as a function which accepted +positional parameters. This calling style will still work for +backwards compatibility, but is deprecated. -=item Moose Often Ovulate Sorta Early +=head2 B -=item Moose Offers Often Super Extensions +Moose's C method supports the L form of C<{into =E $pkg}> +and C<{into_level =E 1}>. -=item Meta Object Orientation Syntax Extensions +B: Doing this is more or less deprecated. Use L +instead, which lets you stack multiple C-alike modules +sanely. It handles getting the exported functions into the right place +for you. -=back +=head2 B + +An alias for C, used by internally by Moose. + +=head1 METACLASS COMPATIBILITY AND MOOSE + +Metaclass compatibility is a thorny subject. You should start by +reading the "About Metaclass compatibility" section in the +C docs. + +Moose will attempt to resolve a few cases of metaclass incompatibility +when you set the superclasses for a class, unlike C, which +simply dies if the metaclasses are incompatible. + +In actuality, Moose fixes incompatibility for I of a class's +metaclasses, not just the class metaclass. That includes the instance +metaclass, attribute metaclass, as well as its constructor class and +destructor class. However, for simplicity this discussion will just +refer to "metaclass", meaning the class metaclass, most of the time. + +Moose has two algorithms for fixing metaclass incompatibility. + +The first algorithm is very simple. If all the metaclass for the +parent is a I of the child's metaclass, then we simply +replace the child's metaclass with the parent's. + +The second algorithm is more complicated. It tries to determine if the +metaclasses only "differ by roles". This means that the parent and +child's metaclass share a common ancestor in their respective +hierarchies, and that the subclasses under the common ancestor are +only different because of role applications. This case is actually +fairly common when you mix and match various C modules, +many of which apply roles to the metaclass. + +If the parent and child do differ by roles, Moose replaces the +metaclass in the child with a newly created metaclass. This metaclass +is a subclass of the parent's metaclass, does all of the roles that +the child's metaclass did before being replaced. Effectively, this +means the new metaclass does all of the roles done by both the +parent's and child's original metaclasses. + +Ultimately, this is all transparent to you except in the case of an +unresolvable conflict. + +=head2 The MooseX:: namespace + +Generally if you're writing an extension I Moose itself you'll want +to put your extension in the C namespace. This namespace is +specifically for extensions that make Moose better or different in some +fundamental way. It is traditionally B for a package that just happens +to use Moose. This namespace follows from the examples of the C +and C namespaces that perform the same function for C and C +respectively. =head1 CAVEATS @@ -546,18 +955,19 @@ more :) =item * -It should be noted that C and C C be used in the same -method. However, they can be combined together with the same class hierarchy; -see F for an example. +It should be noted that C and C B be used in the same +method. However, they may be combined within the same class hierarchy; see +F for an example. -The reason for this is that C is only valid within a method -with the C modifier, and C will never be valid within an -C method. In fact, C will skip over any C methods +The reason for this is that C is only valid within a method +with the C modifier, and C will never be valid within an +C method. In fact, C will skip over any C methods when searching for its appropriate C. -This might seem like a restriction, but I am of the opinion that keeping these -two features separate (but interoperable) actually makes them easy to use, since -their behavior is then easier to predict. Time will tell if I am right or not. +This might seem like a restriction, but I am of the opinion that keeping these +two features separate (yet interoperable) actually makes them easy to use, since +their behavior is then easier to predict. Time will tell whether I am right or +not (UPDATE: so far so good). =back @@ -569,14 +979,14 @@ their behavior is then easier to predict. Time will tell if I am right or not. =item I blame Audrey Tang for then encouraging my meta-model habit in #perl6. -=item Without Yuval "nothingmuch" Kogman this module would not be possible, +=item Without Yuval "nothingmuch" Kogman this module would not be possible, and it certainly wouldn't have this name ;P -=item The basis of the TypeContraints module was Rob Kinyon's idea +=item The basis of the TypeContraints module was Rob Kinyon's idea originally, I just ran with it. -=item Thanks to mst & chansen and the whole #moose poose for all the -ideas/feature-requests/encouragement +=item Thanks to mst & chansen and the whole #moose posse for all the +early ideas/feature-requests/encouragement/bug-finding. =item Thanks to David "Theory" Wheeler for meta-discussions and spelling fixes. @@ -586,43 +996,142 @@ ideas/feature-requests/encouragement =over 4 +=item L + +This is the official web home of Moose, it contains links to our public SVN repo +as well as links to a number of talks and articles on Moose and Moose related +technologies. + +=item L - How to cook a Moose + +=item The Moose is flying, a tutorial by Randal Schwartz + +Part 1 - L + +Part 2 - L + =item L documentation =item The #moose channel on irc.perl.org =item The Moose mailing list - moose@perl.org -=item L +=item Moose stats on ohloh.net - L + +=item Several Moose extension modules in the C namespace. + +See L for extensions. + +=back + +=head2 Books + +=over 4 + +=item The Art of the MetaObject Protocol + +I mention this in the L docs too, this book was critical in +the development of both modules and is highly recommended. + +=back + +=head2 Papers + +=over 4 =item L -This paper (suggested by lbr on #moose) was what lead to the implementation -of the C/C and C/C features. If you really -want to understand this feature, I suggest you read this. +This paper (suggested by lbr on #moose) was what lead to the implementation +of the C/C and C/C features. If you really +want to understand them, I suggest you read this. =back =head1 BUGS -All complex software has bugs lurking in it, and this module is no +All complex software has bugs lurking in it, and this module is no exception. If you find a bug please either email me, or add the bug to cpan-RT. +=head1 FEATURE REQUESTS + +We are very strict about what features we add to the Moose core, especially +the user-visible features. Instead we have made sure that the underlying +meta-system of Moose is as extensible as possible so that you can add your +own features easily. That said, occasionally there is a feature needed in the +meta-system to support your planned extension, in which case you should +either email the mailing list or join us on irc at #moose to discuss. + =head1 AUTHOR -Stevan Little Estevan@iinteractive.comE +Moose is an open project, there are at this point dozens of people who have +contributed, and can contribute. If you have added anything to the Moose +project you have a commit bit on this file and can add your name to the list. + +=head2 CABAL + +However there are only a few people with the rights to release a new version +of Moose. The Moose Cabal are the people to go to with questions regarding +the wider purview of Moose, and help out maintaining not just the code +but the community as well. + +Stevan (stevan) Little Estevan@iinteractive.comE + +Yuval (nothingmuch) Kogman + +Shawn (sartak) Moore + +Dave (autarch) Rolsky Eautarch@urth.orgE + +=head2 OTHER CONTRIBUTORS + +Aankhen + +Adam (Alias) Kennedy + +Anders (Debolaz) Nor Berle + +Nathan (kolibre) Gray + +Christian (chansen) Hansen + +Hans Dieter (confound) Pearcey + +Eric (ewilhelm) Wilhelm + +Guillermo (groditi) Roditi + +Jess (castaway) Robinson + +Matt (mst) Trout + +Robert (phaylon) Sedlacek + +Robert (rlb3) Boone + +Scott (konobi) McWhirter + +Shlomi (rindolf) Fish + +Chris (perigrin) Prather + +Wallace (wreis) Reis + +Jonathan (jrockway) Rockway + +Piotr (dexter) Roszatycki -Christian Hansen Echansen@cpan.orgE +Sam (mugwump) Vilain -Yuval Kogman Enothingmuch@woobling.orgE +... and many other #moose folks =head1 COPYRIGHT AND LICENSE -Copyright 2006 by Infinity Interactive, Inc. +Copyright 2006-2008 by Infinity Interactive, Inc. L This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. +it under the same terms as Perl itself. =cut