X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose.pm;h=ecc880153154b131355134ad3a43685c16d35534;hb=330dbb079ab3e4ff26fb694c232b9c86b2d19161;hp=23f8b5bb3f0c10097522a10033f07a2cb499c8cd;hpb=f6e5456fb2a2e7c5808ef47572322b94e6bc8633;p=gitmo%2FMoose.git diff --git a/lib/Moose.pm b/lib/Moose.pm index 23f8b5b..ecc8801 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -4,13 +4,11 @@ package Moose; use strict; use warnings; -our $VERSION = '0.19'; +our $VERSION = '0.55'; our $AUTHORITY = 'cpan:STEVAN'; -use Scalar::Util 'blessed', 'reftype'; -use Carp 'confess'; -use Sub::Name 'subname'; -use B 'svref_2object'; +use Scalar::Util 'blessed'; +use Carp 'confess', 'croak', 'cluck'; use Sub::Exporter; @@ -22,151 +20,161 @@ use Moose::Meta::TypeCoercion; use Moose::Meta::Attribute; use Moose::Meta::Instance; +use Moose::Meta::Role; + use Moose::Object; use Moose::Util::TypeConstraints; +use Moose::Util (); { my $CALLER; - sub _init_meta { - my $class = $CALLER; + sub init_meta { + my ( $class, $base_class, $metaclass ) = @_; + $base_class = 'Moose::Object' unless defined $base_class; + $metaclass = 'Moose::Meta::Class' unless defined $metaclass; + + confess + "The Metaclass $metaclass must be a subclass of Moose::Meta::Class." + unless $metaclass->isa('Moose::Meta::Class'); # make a subtype for each Moose class - subtype $class - => as 'Object' - => where { $_->isa($class) } - => optimize_as { blessed($_[0]) && $_[0]->isa($class) } - unless find_type_constraint($class); + class_type($class) + unless find_type_constraint($class); my $meta; - if ($class->can('meta')) { + if ( $class->can('meta') ) { # NOTE: - # this is the case where the metaclass pragma - # was used before the 'use Moose' statement to + # 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"; + ( blessed($meta) && $meta->isa('Moose::Meta::Class') ) + || confess "You already have a &meta function, but it does not return a Moose::Meta::Class"; } 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]); - }) + # 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 = $metaclass->initialize($class); + $meta->add_method( + 'meta' => sub { + # re-initialize so it inherits properly + $metaclass->initialize( blessed( $_[0] ) || $_[0] ); + } + ); } # make sure they inherit from Moose::Object - $meta->superclasses('Moose::Object') - unless $meta->superclasses(); + $meta->superclasses($base_class) + unless $meta->superclasses(); + + return $meta; } my %exports = ( extends => sub { my $class = $CALLER; - return subname 'Moose::extends' => sub (@) { - confess "Must derive at least one class" unless @_; - Class::MOP::load_class($_) for @_; - # this checks the metaclass to make sure - # it is correct, sometimes it can get out + return Class::MOP::subname('Moose::extends' => sub (@) { + 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 = $class->meta->_fix_metaclass_incompatability(@_); - $meta->superclasses(@_); - }; + my $meta = $class->meta->_fix_metaclass_incompatability(@supers); + $meta->superclasses(@supers); + }); }, with => sub { my $class = $CALLER; - return subname 'Moose::with' => sub (@) { - my (@roles) = @_; - confess "Must specify at least one role" unless @roles; - Class::MOP::load_class($_) for @roles; - $class->meta->_apply_all_roles(@roles); - }; + return Class::MOP::subname('Moose::with' => sub (@) { + Moose::Util::apply_all_roles($class->meta, @_) + }); }, has => sub { my $class = $CALLER; - return subname 'Moose::has' => sub ($;%) { - my ($name, %options) = @_; - my $attrs = (ref($name) eq 'ARRAY') ? $name : [($name)]; - $class->meta->_process_attribute($_, %options) for @$attrs; - }; + return Class::MOP::subname('Moose::has' => sub ($;%) { + my $name = shift; + croak 'Usage: has \'name\' => ( key => value, ... )' if @_ == 1; + my %options = @_; + my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ]; + $class->meta->add_attribute( $_, %options ) for @$attrs; + }); }, before => sub { my $class = $CALLER; - return subname 'Moose::before' => sub (@&) { - my $code = pop @_; - my $meta = $class->meta; - $meta->add_before_method_modifier($_, $code) for @_; - }; + return Class::MOP::subname('Moose::before' => sub (@&) { + Moose::Util::add_method_modifier($class, 'before', \@_); + }); }, after => sub { my $class = $CALLER; - return subname 'Moose::after' => sub (@&) { - my $code = pop @_; - my $meta = $class->meta; - $meta->add_after_method_modifier($_, $code) for @_; - }; + return Class::MOP::subname('Moose::after' => sub (@&) { + Moose::Util::add_method_modifier($class, 'after', \@_); + }); }, around => sub { - my $class = $CALLER; - return subname 'Moose::around' => sub (@&) { - my $code = pop @_; - my $meta = $class->meta; - $meta->add_around_method_modifier($_, $code) for @_; - }; + my $class = $CALLER; + return Class::MOP::subname('Moose::around' => sub (@&) { + Moose::Util::add_method_modifier($class, 'around', \@_); + }); }, super => sub { - return subname 'Moose::super' => sub {}; + return Class::MOP::subname('Moose::super' => sub { + return unless our $SUPER_BODY; $SUPER_BODY->(our @SUPER_ARGS) + }); }, override => sub { my $class = $CALLER; - return subname 'Moose::override' => sub ($&) { - my ($name, $method) = @_; - $class->meta->add_override_method_modifier($name => $method); - }; + return Class::MOP::subname('Moose::override' => sub ($&) { + my ( $name, $method ) = @_; + $class->meta->add_override_method_modifier( $name => $method ); + }); }, inner => sub { - return subname 'Moose::inner' => sub {}; + return Class::MOP::subname('Moose::inner' => sub { + 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; + } + }); }, augment => sub { my $class = $CALLER; - return subname 'Moose::augment' => sub (@&) { - my ($name, $method) = @_; - $class->meta->add_augment_method_modifier($name => $method); - }; + return Class::MOP::subname('Moose::augment' => sub (@&) { + my ( $name, $method ) = @_; + $class->meta->add_augment_method_modifier( $name => $method ); + }); }, - - # 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->(@_); - # }); - # }; - # }, - + make_immutable => sub { + my $class = $CALLER; + return Class::MOP::subname('Moose::make_immutable' => sub { + cluck "The make_immutable keyword has been deprecated, " . + "please go back to __PACKAGE__->meta->make_immutable\n"; + $class->meta->make_immutable(@_); + }); + }, confess => sub { return \&Carp::confess; }, @@ -175,71 +183,107 @@ use Moose::Util::TypeConstraints; }, ); - my $exporter = Sub::Exporter::build_exporter({ - exports => \%exports, - groups => { - default => [':all'] + my $exporter = Sub::Exporter::build_exporter( + { + exports => \%exports, + groups => { default => [':all'] } } - }); - - sub import { - $CALLER = caller(); - + ); + + # 1 extra level because it's called by import so there's a layer of indirection + sub _get_caller{ + my $offset = 1; + return + (ref $_[1] && defined $_[1]->{into}) + ? $_[1]->{into} + : (ref $_[1] && defined $_[1]->{into_level}) + ? caller($offset + $_[1]->{into_level}) + : caller($offset); + } + + sub import { + $CALLER = _get_caller(@_); + + # this works because both pragmas set $^H (see perldoc perlvar) + # which affects the current compilation - i.e. the file who use'd + # us - which is why we don't need to do anything special to make + # it affect that file rather than this one (which is already compiled) + strict->import; - warnings->import; + warnings->import; # we should never export to main return if $CALLER eq 'main'; - - _init_meta(); - + + init_meta( $CALLER, 'Moose::Object' ); + goto $exporter; } + # NOTE: + # This is for special use by + # some modules and stuff, I + # dont know if it is sane enough + # to document actually. + # - SL + sub __CURRY_EXPORTS_FOR_CLASS__ { + $CALLER = shift; + ($CALLER ne 'Moose') + || croak "_import_into must be called a function, not a method"; + ($CALLER->can('meta') && $CALLER->meta->isa('Class::MOP::Class')) + || croak "Cannot call _import_into on a package ($CALLER) without a metaclass"; + return map { $_ => $exports{$_}->() } (@_ ? @_ : keys %exports); + } + sub unimport { - no strict 'refs'; - my $class = caller(); + no strict 'refs'; + my $class = _get_caller(@_); + # loop through the exports ... - foreach my $name (keys %exports) { - next if $name =~ /inner|super|self/; - + foreach my $name ( keys %exports ) { + # if we find one ... - if (defined &{$class . '::' . $name}) { - my $keyword = \&{$class . '::' . $name}; - + 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 $@; + my ($pkg_name) = Class::MOP::get_code_info($keyword); next if $pkg_name ne 'Moose'; - + # and if it is from Moose then undef the slot - delete ${$class . '::'}{$name}; + delete ${ $class . '::' }{$name}; } } } - - + } ## make 'em all immutable $_->meta->make_immutable( inline_constructor => 0, - inline_accessors => 0, -) for ( + inline_accessors => 1, # these are Class::MOP accessors, so they need inlining + ) + for ( 'Moose::Meta::Attribute', 'Moose::Meta::Class', 'Moose::Meta::Instance', 'Moose::Meta::TypeConstraint', 'Moose::Meta::TypeConstraint::Union', + 'Moose::Meta::TypeConstraint::Parameterized', 'Moose::Meta::TypeCoercion', 'Moose::Meta::Method', 'Moose::Meta::Method::Accessor', 'Moose::Meta::Method::Constructor', + 'Moose::Meta::Method::Destructor', 'Moose::Meta::Method::Overriden', -); + + 'Moose::Meta::Role', + 'Moose::Meta::Role::Method', + 'Moose::Meta::Role::Method::Required', + ); 1; @@ -249,80 +293,54 @@ __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 DESCRIPTION -Moose is an extension of the Perl 5 object system. - -=head2 Another object system!?!? +Moose is an extension of the Perl 5 object system. -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. +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. -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. +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. -=head2 Is this for real? Or is this just an experiment? +=head2 Moose Extensions -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. - -=head2 Is this ready for use in production? - -Yes, I believe that it is. - -I have two medium-to-large-ish web applications which use Moose heavily -and have been in production (without issue) for several months now. At -$work, we are re-writing our core offering in it. And several people on -#moose have been using it (in production) for several months now as well. - -Of course, in the end, you need to make this call yourself. If you have -any questions or concerns, please feel free to email me, or even the list -or just stop by #moose and ask away. - -=head2 Is Moose just Perl 6 in Perl 5? - -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 L namespace is the official place to find Moose extensions. +There are a number of these modules out on CPAN right now the best way to +find them is to search for MooseX:: on search.cpan.org or to look at the +latest version of L which aims to keep an up to date, easily +installable list of these extensions. =head1 BUILDING CLASSES WITH MOOSE @@ -330,20 +348,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 @@ -351,63 +368,75 @@ 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 %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 +This will install an attribute of a given C<$name> into the current class. +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 +I, I and I 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 +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. +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)> @@ -417,65 +446,50 @@ 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. - -=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. I will try and write a -recipe on it soon. - -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 it 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 just default to using -B as the metaclass name. +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. -=item I ARRAY | HASH | REGEXP | CODE> +=item I ARRAY | HASH | REGEXP | ROLE | CODE> -The handles option provides Moose classes with automated delegation features. -This is a pretty complex and powerful option, it accepts many different option -formats, each with it's own benefits and drawbacks. +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 This features is no longer experimental, but it still may have subtle -bugs lurking in the deeper corners. So if you think you have found a bug, you -probably have, so please report it to me right away. +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. -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: -All handles 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 a locally defined method with a delegated method, an -exception will be thrown if you try. Meaning, 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 cannot override any of the methods found in Moose::Object as well as -C or 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 because it usually tends to break your -class. And as with overriding locally defined methods, if you do want to do this, -you should do it manually and 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: @@ -483,80 +497,142 @@ Below is the documentation for each option format: =item C -This is the most common usage for handles. You basically pass a list of -method names to be delegated, and Moose will install a delegation method -for each one in the list. +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 handles. Instead of a list of -method names, you pass a HASH ref where the key is the method name you -want installed locally, and the value is the name of the original method -in the class being delegated too. +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 +This can be very useful for recursive classes like trees. Here is a quick example (soon to be expanded into a Moose::Cookbook::Recipe): - pacakge Tree; + package Tree; use Moose; - + has 'node' => (is => 'rw', isa => 'Any'); - + has 'children' => ( is => 'ro', isa => 'ArrayRef', default => sub { [] } ); - + has 'parent' => ( is => 'rw', isa => 'Tree', - is_weak_ref => 1, + weak_ref => 1, handles => { parent_node => 'node', - siblings => 'children', + siblings => 'children', } ); -In this example, the Tree package gets the C and C methods -which delegate to the C and C methods of the Tree instance stored -in the parent slot. +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 too, then filters that list using the regexp supplied here. +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. +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 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 too. The second is the metaclass -of the class being delegated too. It expects you to return a hash (not a HASH ref) -of the methods you want mapped. +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. This too is an advanced +topic, we don't yet have a cookbook for it though. + +As with I, the default behavior is to just load C<$role_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 trait. If there is no +C method, it will fall back to using +B as the trait name. + =back =item B %options> -This is variation on the normal attibute creator C, which allows you to -clone and extend an attribute from a superclass. Here is a quick example: +This is variation on the normal attibute 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', + is => 'rw', isa => 'Str', default => 'Hello, I am a Foo' ); @@ -564,28 +640,29 @@ clone and extend an attribute from a superclass. Here is a quick example: package My::Foo; use Moose; - extends 'Foo'; + with 'Foo::Role'; has '+message' => (default => 'Hello I am My::Foo'); -What is happening here is that B is cloning the C attribute -from it's parent class B, retaining the is =E 'rw' and isa =E 'Str' -characteristics, but changing the value in C. +In this case, we are basically taking the attribute which the role supplied +and altering it within the bounds of this feature. -This feature is restricted somewhat, so as to try and enfore at least I -sanity into it. You are only allowed to change the following attributes: +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 +=item I Change the default value of an attribute. -=item I +=item I Change whether the attribute attempts to coerce a value passed to it. -=item I +=item I Change if the attribute is required to have a value. @@ -593,10 +670,39 @@ Change if the attribute is required to have a value. 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, but if and B the new type is -a subtype of the old type. +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 descision. + +=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 @@ -606,54 +712,55 @@ a subtype of the old type. =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 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: @@ -662,39 +769,52 @@ 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 :) +Moose also offers some options for extending or embedding it into your own +framework. The basic premise is to have something that sets up your class' +metaclass and export the moose declarators (C, C, C,...). +Here is an example: -=over 4 + package MyFramework; + use Moose; -=item Make Other Object Systems Envious + sub import { + my $CALLER = caller(); -=item Makes Object Orientation So Easy + strict->import; + warnings->import; -=item Makes Object Orientation Spiffy- Er (sorry ingy) + # we should never export to main + return if $CALLER eq 'main'; + Moose::init_meta( $CALLER, 'MyFramework::Base' ); + Moose->import({into => $CALLER}); -=item Most Other Object Systems Emasculate + # Do my custom framework stuff -=item Moose Often Ovulate Sorta Early + return 1; + } -=item Moose Offers Often Super Extensions +=head2 B -=item Meta Object Orientation Syntax Extensions +Moose's C method supports the L form of C<{into =E $pkg}> +and C<{into_level =E 1}> -=back +=head2 B + +Moose does some boot strapping: it creates a metaclass object for your class, +and then injects a C accessor into your class to retrieve it. Then it +sets your baseclass to Moose::Object or the value you pass in unless you already +have one. This is all done via C which takes the name of your class +and optionally a baseclass and a metaclass as arguments. =head1 CAVEATS @@ -702,18 +822,88 @@ 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). + +=item * + +It is important to note that we currently have no simple way of combining +multiple extended versions of Moose (see L above), +and that in many cases they will conflict with one another. We are working on +developing a way around this issue, but in the meantime, you have been warned. + +=back + +=head1 JUSTIFICATION + +In case you are still asking yourself "Why do I need this?", then this +section is for you. This used to be part of the main DESCRIPTION, but +I think Moose no longer actually needs justification, so it is included +(read: buried) here for those who are still not convinced. + +=over 4 + +=item Another object system!?!? + +Yes, I know there has been an explosion recently of new ways to +build objects 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. + +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. + +=item Is this for real? Or is this just an experiment? + +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. + +=item Is this ready for use in production? + +Yes, I believe that it is. + +Moose has been used successfully in production environemnts by several people +and companies (including the one I work for). There are Moose applications +which have been in production with little or no issue now for well over two years. +I consider it highly stable and we are commited to keeping it stable. + +Of course, in the end, you need to make this call yourself. If you have +any questions or concerns, please feel free to email me, or even the list +or just stop by #moose and ask away. + +=item Is Moose just Perl 6 in Perl 5? + +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 of +writing the same old boring Perl 5 OO code, and drooling over Perl 6 OO. So +instead of switching to Ruby, I wrote Moose :) + +=item Wait, I modern, I thought it was just I? + +So I was reading Larry Wall's talk from the 1999 Linux World entitled +"Perl, the first postmodern computer language" in which he talks about how +he picked the features for Perl because he thought they were cool and he +threw out the ones that he thought sucked. This got me thinking about how +we have done the same thing in Moose. For Moose, we have "borrowed" features +from Perl 6, CLOS (LISP), Smalltalk, Java, BETA, OCaml, Ruby and more, and +the bits we didn't like (cause they sucked) we tossed aside. So for this +reason (and a few others) I have re-dubbed Moose a I object system. + +Nuff Said. =back @@ -725,14 +915,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/bug-finding. +=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. @@ -742,43 +932,119 @@ ideas/feature-requests/encouragement/bug-finding. =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 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 L namespace. + +=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 -Christian Hansen Echansen@cpan.orgE +B + +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 + +Yuval (nothingmuch) Kogman + +Chris (perigrin) Prather + +Wallace (wreis) Reis + +Jonathan (jrockway) Rockway + +Piotr (dexter) Roszatycki + +Sam (mugwump) Vilain + +Shawn (sartak) Moore -Yuval Kogman Enothingmuch@woobling.orgE +... and many other #moose folks =head1 COPYRIGHT AND LICENSE -Copyright 2006, 2007 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