X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose.pm;h=9b8c5ebb435352f451f9bcace76c20a5f5406dfc;hb=52c7c33051150fe0851c98369b6c4cb25a1779c1;hp=150bc3192ae0ec25590b05740a004088bf66e1dd;hpb=2a0f3bd393ed7ba46c220243df34ddc63bbb85ac;p=gitmo%2FMoose.git diff --git a/lib/Moose.pm b/lib/Moose.pm index 150bc31..9b8c5eb 100644 --- a/lib/Moose.pm +++ b/lib/Moose.pm @@ -4,7 +4,8 @@ package Moose; use strict; use warnings; -our $VERSION = '0.13'; +our $VERSION = '0.21'; +our $AUTHORITY = 'cpan:STEVAN'; use Scalar::Util 'blessed', 'reftype'; use Carp 'confess'; @@ -34,6 +35,7 @@ use Moose::Util::TypeConstraints; subtype $class => as 'Object' => where { $_->isa($class) } + => optimize_as { blessed($_[0]) && $_[0]->isa($class) } unless find_type_constraint($class); my $meta; @@ -70,7 +72,7 @@ use Moose::Util::TypeConstraints; my $class = $CALLER; return subname 'Moose::extends' => sub (@) { confess "Must derive at least one class" unless @_; - _load_all_classes(@_); + Class::MOP::load_class($_) for @_; # this checks the metaclass to make sure # it is correct, sometimes it can get out # of sync when the classes are being built @@ -83,15 +85,16 @@ use Moose::Util::TypeConstraints; return subname 'Moose::with' => sub (@) { my (@roles) = @_; confess "Must specify at least one role" unless @roles; - _load_all_classes(@roles); + Class::MOP::load_class($_) for @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); + my ($name, %options) = @_; + my $attrs = (ref($name) eq 'ARRAY') ? $name : [($name)]; + $class->meta->_process_attribute($_, %options) for @$attrs; }; }, before => sub { @@ -119,6 +122,11 @@ use Moose::Util::TypeConstraints; }; }, super => sub { + { + our %SUPER_SLOT; + no strict 'refs'; + $SUPER_SLOT{$CALLER} = \*{"${CALLER}::super"}; + } return subname 'Moose::super' => sub {}; }, override => sub { @@ -129,6 +137,11 @@ use Moose::Util::TypeConstraints; }; }, inner => sub { + { + our %INNER_SLOT; + no strict 'refs'; + $INNER_SLOT{$CALLER} = \*{"${CALLER}::inner"}; + } return subname 'Moose::inner' => sub {}; }, augment => sub { @@ -198,7 +211,6 @@ use Moose::Util::TypeConstraints; 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}) { @@ -214,35 +226,29 @@ use Moose::Util::TypeConstraints; } } } + + } -## 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 'em all immutable -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; -} +$_->meta->make_immutable( + inline_constructor => 0, + inline_accessors => 0, +) for ( + 'Moose::Meta::Attribute', + 'Moose::Meta::Class', + 'Moose::Meta::Instance', + + 'Moose::Meta::TypeConstraint', + 'Moose::Meta::TypeConstraint::Union', + 'Moose::Meta::TypeCoercion', + + 'Moose::Meta::Method', + 'Moose::Meta::Method::Accessor', + 'Moose::Meta::Method::Constructor', + 'Moose::Meta::Method::Overriden', +); 1; @@ -282,18 +288,7 @@ Moose - A complete modern object system for Perl 5 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 @@ -312,13 +307,24 @@ 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 Can I use this in production? Or is this just an experiment? +=head2 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. 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. +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? @@ -368,7 +374,7 @@ superclasses still properly inherit from L. 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. -=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 @@ -428,6 +434,22 @@ If an attribute is marked as lazy it B have a default supplied. 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. + =item I $code> The trigger option is a CODE reference which will be called after the value of @@ -436,10 +458,154 @@ 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. -=item I [ @handles ]> +=item I ARRAY | HASH | REGEXP | 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. + +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. + +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. 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 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. + +Below is the documentation for each option format: + +=over 4 + +=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. + +=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 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): + + pacakge 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, + handles => { + parent_node => 'node', + 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. + +=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 + +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 + +=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: + + 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 it's parent class B, retaining the is =E 'rw' and isa =E 'Str' +characteristics, but changing the value in C. + +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: + +=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 -There is experimental support for attribute delegation using the C -option. More docs to come later. +You I allowed to change the type, but if and B the new type is +a subtype of the old type. =back @@ -575,7 +741,7 @@ and it certainly wouldn't have this name ;P originally, I just ran with it. =item Thanks to mst & chansen and the whole #moose poose for all the -ideas/feature-requests/encouragement +ideas/feature-requests/encouragement/bug-finding. =item Thanks to David "Theory" Wheeler for meta-discussions and spelling fixes. @@ -617,7 +783,7 @@ Yuval Kogman Enothingmuch@woobling.orgE =head1 COPYRIGHT AND LICENSE -Copyright 2006 by Infinity Interactive, Inc. +Copyright 2006, 2007 by Infinity Interactive, Inc. L