X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose.pm;h=eb00d7f17f9c0e440cc3216689b05310e2ea937d;hb=30350cb4d7b4345131ed638b2b30e7d1b7b1ef4c;hp=b4b75b0c0cf5b6d09bc2c62a87eab5ea4a354a07;hpb=0779da922a64aa891bc2708b6fc8de4d4fdffa11;p=gitmo%2FMoose.git diff --git a/lib/Moose.pm b/lib/Moose.pm index b4b75b0..eb00d7f 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -4,7 +4,10 @@ package Moose; use strict; use warnings; -our $VERSION = '0.56'; +use 5.008; + +our $VERSION = '0.65'; +$VERSION = eval $VERSION; our $AUTHORITY = 'cpan:STEVAN'; use Scalar::Util 'blessed'; @@ -12,7 +15,7 @@ use Carp 'confess', 'croak', 'cluck'; use Moose::Exporter; -use Class::MOP 0.64; +use Class::MOP 0.76; use Moose::Meta::Class; use Moose::Meta::TypeConstraint; @@ -29,11 +32,23 @@ 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::Meta::Role::Application::ToMetaclassInstance; use Moose::Util::TypeConstraints; use Moose::Util (); +sub _caller_info { + my $level = @_ ? ($_[0] + 1) : 2; + my %info; + @info{qw(package file line)} = caller($level); + return \%info; +} + +sub throw_error { + # FIXME This + shift; + goto \&confess +} + sub extends { my $class = shift; @@ -53,7 +68,7 @@ sub extends { # 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::MOP::Class->initialize($class)->_fix_metaclass_incompatability(@supers); + my $meta = Moose::Meta::Class->initialize($class); $meta->superclasses(@supers); } @@ -66,7 +81,7 @@ sub has { my $class = shift; my $name = shift; croak 'Usage: has \'name\' => ( key => value, ... )' if @_ == 1; - my %options = @_; + my %options = ( definition_context => _caller_info(), @_ ); my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ]; Class::MOP::Class->initialize($class)->add_attribute( $_, %options ) for @$attrs; } @@ -86,8 +101,15 @@ sub around { Moose::Util::add_method_modifier($class, 'around', \@_); } +our $SUPER_PACKAGE; +our $SUPER_BODY; +our @SUPER_ARGS; + sub super { - return unless our $SUPER_BODY; $SUPER_BODY->(our @SUPER_ARGS); + # This check avoids a recursion loop - see + # t/100_bugs/020_super_recursion.t + return if defined $SUPER_PACKAGE && $SUPER_PACKAGE ne caller(); + return unless $SUPER_BODY; $SUPER_BODY->(@SUPER_ARGS); } sub override { @@ -116,16 +138,9 @@ sub augment { 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 ) + qw( extends with has before after around override augment) ], as_is => [ qw( super inner ), @@ -149,12 +164,11 @@ sub init_meta { my %args = @_; my $class = $args{for_class} - or confess "Cannot call init_meta without specifying a 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'; - confess - "The Metaclass $metaclass must be a subclass of Moose::Meta::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 @@ -162,27 +176,63 @@ sub init_meta { unless find_type_constraint($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 { + # 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; + } + } + } + + $meta = $metaclass->initialize($class); + } + if ( $class->can('meta') ) { + # check 'meta' method + + # it may be inherited + # NOTE: # this is the case where the metaclass pragma # was used before the 'use Moose' statement to # override a specific class - $meta = Class::MOP::Class->initialize($class); - ( blessed($meta) && $meta->isa('Moose::Meta::Class') ) - || confess "You already have a &meta function, but it does not return a Moose::Meta::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; } - 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 = $metaclass->initialize($class); + + 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( blessed( $_[0] ) || $_[0] ); + $metaclass->initialize( ref($_[0]) || $_[0] ); } ); } @@ -191,7 +241,6 @@ sub init_meta { $meta->superclasses($base_class) unless $meta->superclasses(); - return $meta; } @@ -202,23 +251,18 @@ sub _get_caller { ## make 'em all immutable -$_->meta->make_immutable( +$_->make_immutable( inline_constructor => 1, constructor_name => "_new", - inline_accessors => 1, # these are Class::MOP accessors, so they need inlining - ) - for (qw( + # these are Class::MOP accessors, so they need inlining + inline_accessors => 1 + ) for grep { $_->is_mutable } + map { $_->meta } + qw( Moose::Meta::Attribute Moose::Meta::Class Moose::Meta::Instance - Moose::Meta::TypeConstraint - Moose::Meta::TypeConstraint::Union - Moose::Meta::TypeConstraint::Parameterized - Moose::Meta::TypeConstraint::Enum - Moose::Meta::TypeConstraint::Class - Moose::Meta::TypeConstraint::Role - Moose::Meta::TypeConstraint::Registry Moose::Meta::TypeCoercion Moose::Meta::TypeCoercion::Union @@ -240,8 +284,7 @@ $_->meta->make_immutable( Moose::Meta::Role::Application::ToClass Moose::Meta::Role::Application::ToRole Moose::Meta::Role::Application::ToInstance - Moose::Meta::Role::Application::ToMetaclassInstance -)); +); 1; @@ -285,20 +328,23 @@ Moose is an extension of the Perl 5 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. +more about what you want to do and less about the mechanics of OOP. -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. +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 New to Moose? -If you're new to Moose, the best place to start is the -L. The 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. +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. + +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 Moose Extensions @@ -357,12 +403,13 @@ superclasses still properly inherit from L. This will apply a given set of C<@roles> to the local class. -=item B %options> +=item B %options> -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): +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 @@ -372,10 +419,12 @@ 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, however if you use those, you won't need the I -option. +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> @@ -426,7 +475,11 @@ The I option is a CODE reference which will be called after the value o 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). You B have a trigger on a read-only -attribute. +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> @@ -561,11 +614,58 @@ resolved to a class name. Also see L for a metaclass trait example. +=item I => Str + +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 => SCALAR | CODE + +The value of this key is the default value which will initialize the attribute. + +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. + +=item I => Str + +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 => Str + +Allows you to clear the value, see the L for more +information. + +=item I => Str + +Basic test to see if a value has been set in the attribute, see the +L for more +information. + +=item I => (0|1) + +Automatically define lazy => 1 as well as builder => "_build_$attr", clearer => +"clear_$attr', predicate => 'has_$attr' unless they are already defined. + + =back =item B %options> -This is variation on the normal attibute creator C which allows you to +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: @@ -644,7 +744,7 @@ 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. +policy decision. =item I @@ -772,46 +872,10 @@ to work. Here is an example: =head1 EXTENDING AND EMBEDDING MOOSE -Moose also offers some options for extending or embedding it into your -own framework. There are several things you might want to do as part -of such a framework. First, you probably want to export Moose's sugar -functions (C, C, etc) for users of the -framework. Second, you may want to provide additional sugar of your -own. Third, you may want to provide your own object base class instead -of L, and/or your own metaclass class instead of -L. - -The exporting needs can be asily satisfied by using -L, which is what C itself uses for -exporting. L lets you "export like Moose". - -If you define an C method in a module that uses -L, then this method will be called I -C's own C. This gives you a chance to provide an -alternate object base class or metaclass class. - -Here is a simple example: - - package MyFramework; - - use strict; - use warnings; - - use Moose (); # no need to get Moose's exports - use Moose::Exporter; - - Moose::Exporter->setup_import_methods( also => 'Moose' ); - - sub init_meta { - shift; - return Moose->init_meta( @_, base_class => 'MyFramework::Base' ); - } - -In this example, any class that includes C will get -all of C's sugar functions, and will have their superclass -set to C. - -Additionally, that class can include C to unimport +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. =head2 B<< Moose->init_meta(for_class => $class, base_class => $baseclass, metaclass => $metaclass) >> @@ -838,6 +902,60 @@ instead, which lets you stack multiple C-alike modules sanely. It handles getting the exported functions into the right place for you. +=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 =over 4 @@ -858,75 +976,6 @@ 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 =head1 ACKNOWLEDGEMENTS @@ -970,6 +1019,8 @@ Part 2 - L =item L documentation +=item L for information about type constraints. + =item The #moose channel on irc.perl.org =item The Moose mailing list - moose@perl.org @@ -1022,9 +1073,26 @@ 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. -B +Stevan (stevan) Little Estevan@iinteractive.comE + +Yuval (nothingmuch) Kogman + +Shawn (sartak) Moore + +Dave (autarch) Rolsky Eautarch@urth.orgE + +=head2 OTHER CONTRIBUTORS Aankhen @@ -1054,8 +1122,6 @@ Scott (konobi) McWhirter Shlomi (rindolf) Fish -Yuval (nothingmuch) Kogman - Chris (perigrin) Prather Wallace (wreis) Reis @@ -1066,7 +1132,7 @@ Piotr (dexter) Roszatycki Sam (mugwump) Vilain -Shawn (sartak) Moore +Cory (gphat) Watson ... and many other #moose folks