X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose.pm;h=c54d8db6a804f5bf28c682e2c22fcba5d7e72d5f;hb=bb6c833559f9e6ac403628d8ec4d09af2a0477e1;hp=d2cd2f30cbc2330c49d493a7edd5e640597b656c;hpb=085fba615666e2297e8bc2d965b37ce4f0eb1182;p=gitmo%2FMoose.git diff --git a/lib/Moose.pm b/lib/Moose.pm index d2cd2f3..c54d8db 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.57'; +$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.65; use Moose::Meta::Class; use Moose::Meta::TypeConstraint; @@ -20,12 +23,25 @@ use Moose::Meta::TypeCoercion; 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::Object; use Moose::Util::TypeConstraints; use Moose::Util (); +sub throw_error { + # FIXME This + shift; + goto \&confess +} + sub extends { my $class = shift; @@ -45,13 +61,13 @@ 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->meta->_fix_metaclass_incompatability(@supers); + my $meta = Moose::Meta::Class->initialize($class)->_fix_metaclass_incompatability(@supers); $meta->superclasses(@supers); } sub with { my $class = shift; - Moose::Util::apply_all_roles($class->meta, @_); + Moose::Util::apply_all_roles(Class::MOP::Class->initialize($class), @_); } sub has { @@ -60,7 +76,7 @@ sub has { 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; + Class::MOP::Class->initialize($class)->add_attribute( $_, %options ) for @$attrs; } sub before { @@ -85,7 +101,7 @@ sub super { sub override { my $class = shift; my ( $name, $method ) = @_; - $class->meta->add_override_method_modifier( $name => $method ); + Class::MOP::Class->initialize($class)->add_override_method_modifier( $name => $method ); } sub inner { @@ -105,17 +121,17 @@ sub inner { sub augment { my $class = shift; my ( $name, $method ) = @_; - $class->meta->add_augment_method_modifier( $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->meta->make_immutable(@_); + Class::MOP::Class->initialize($class)->make_immutable(@_); } -my $exporter = Moose::Exporter->build_import_methods( +Moose::Exporter->setup_import_methods( with_caller => [ qw( extends with has before after around override augment make_immutable ) ], @@ -141,12 +157,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 @@ -154,27 +169,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_incompatability, 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->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 $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] ); } ); } @@ -183,7 +234,6 @@ sub init_meta { $meta->superclasses($base_class) unless $meta->superclasses(); - return $meta; } @@ -195,29 +245,45 @@ sub _get_caller { ## make 'em all immutable $_->meta->make_immutable( - inline_constructor => 0, + inline_constructor => 1, + constructor_name => "_new", 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', - ); + 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; @@ -261,12 +327,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. + +=head2 New to Moose? -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. +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 @@ -521,16 +598,13 @@ B as the metaclass name. 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. +allows you to use more than one extension at a time. -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. +See L for details on how a trait name is +resolved to a class name. + +Also see L for a metaclass trait +example. =back @@ -690,6 +764,36 @@ C anywhere you need to test for an object's class name. =back +=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 @@ -713,44 +817,39 @@ 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. 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: - - package MyFramework; - use Moose; +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. - sub import { - my $CALLER = caller(); +=head2 B<< Moose->init_meta(for_class => $class, base_class => $baseclass, metaclass => $metaclass) >> - strict->import; - warnings->import; +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. - # we should never export to main - return if $CALLER eq 'main'; - Moose::init_meta( $CALLER, 'MyFramework::Base' ); - Moose->import({into => $CALLER}); +You can specify an alternate metaclass with the C parameter. - # Do my custom framework stuff +For more detail on this topic, see L. - return 1; - } +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. =head2 B Moose's C method supports the L form of C<{into =E $pkg}> -and C<{into_level =E 1}> +and C<{into_level =E 1}>. -=head2 B +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. -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. +=head2 throw_error -For more detail on this topic, see L. +An alias for C, used by internally by Moose. =head1 CAVEATS @@ -772,75 +871,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 @@ -976,6 +1006,8 @@ Wallace (wreis) Reis Jonathan (jrockway) Rockway +Dave (autarch) Rolsky + Piotr (dexter) Roszatycki Sam (mugwump) Vilain