foo
[gitmo/Moose.git] / lib / Moose.pm
index 6917896..7756cb4 100644 (file)
@@ -4,7 +4,7 @@ package Moose;
 use strict;
 use warnings;
 
-our $VERSION = '0.05';
+our $VERSION = '0.09_03';
 
 use Scalar::Util 'blessed', 'reftype';
 use Carp         'confess';
@@ -25,13 +25,11 @@ use Moose::Object;
 use Moose::Util::TypeConstraints;
 
 {
-    my ( $CALLER, %METAS );
+    my $CALLER;
 
-    sub _find_meta {
+    sub _init_meta {
         my $class = $CALLER;
 
-        return $METAS{$class} if exists $METAS{$class};
-
         # make a subtype for each Moose class
         subtype $class
             => as 'Object'
@@ -65,35 +63,85 @@ use Moose::Util::TypeConstraints;
         # make sure they inherit from Moose::Object
         $meta->superclasses('Moose::Object')
            unless $meta->superclasses();
-
-        return $METAS{$class} = $meta;
     }
 
     my %exports = (
         extends => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::extends' => sub {
+            my $class = $CALLER;
+            return subname 'Moose::extends' => sub ($;@) {
                 _load_all_classes(@_);
-                $meta->superclasses(@_)
+                my $meta = $class->meta;
+                foreach my $super (@_) {
+                    # don't bother if it does not have a meta.
+                    next unless $super->can('meta');
+                    # if it's meta is a vanilla Moose, 
+                    # then we can safely ignore it.
+                    next if blessed($super->meta) eq 'Moose::Meta::Class';
+                    # but if we have anything else, 
+                    # we need to check it out ...
+                    unless (# see if of our metaclass is incompatible
+                            ($meta->isa(blessed($super->meta)) &&
+                             # and see if our instance metaclass is incompatible
+                             $meta->instance_metaclass->isa($super->meta->instance_metaclass)) &&
+                            # ... and if we are just a vanilla Moose
+                            $meta->isa('Moose::Meta::Class')) {
+                        # re-initialize the meta ...
+                        my $super_meta = $super->meta;
+                        # NOTE:
+                        # We might want to consider actually 
+                        # transfering any attributes from the 
+                        # original meta into this one, but in 
+                        # general you should not have any there
+                        # at this point anyway, so it's very 
+                        # much an obscure edge case anyway
+                        $meta = $super_meta->reinitialize($class => (
+                            ':attribute_metaclass' => $super_meta->attribute_metaclass,                            
+                            ':method_metaclass'    => $super_meta->method_metaclass,
+                            ':instance_metaclass'  => $super_meta->instance_metaclass,
+                        ));
+                    }
+                }
+                $meta->superclasses(@_);
             };
         },
         with => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::with' => sub {
-                my ($role) = @_;
-                _load_all_classes($role);
-                $role->meta->apply($meta);
+            my $class = $CALLER;
+            return subname 'Moose::with' => sub ($;@) {
+                my (@roles) = @_;
+                _load_all_classes(@roles);
+                ($_->can('meta') && $_->meta->isa('Moose::Meta::Role'))
+                    || confess "You can only consume roles, $_ is not a Moose role"
+                        foreach @roles;
+                if (scalar @roles == 1) {
+                    $roles[0]->meta->apply($class->meta);
+                }
+                else {
+                    Moose::Meta::Role->combine(
+                        map { $_->meta } @roles
+                    )->apply($class->meta);
+                }
             };
         },
         has => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::has' => sub {
-                my ($name, %options) = @_;
+            my $class = $CALLER;
+            return subname 'Moose::has' => sub ($;%) {
+                my ($name, %options) = @_;              
+                my $meta = $class->meta;
                 if ($name =~ /^\+(.*)/) {
                     my $inherited_attr = $meta->find_attribute_by_name($1);
                     (defined $inherited_attr)
                         || confess "Could not find an attribute by the name of '$1' to inherit from";
-                    my $new_attr = $inherited_attr->clone_and_inherit_options(%options);
+                    my $new_attr;
+                    if ($inherited_attr->isa('Moose::Meta::Attribute')) {
+                        $new_attr = $inherited_attr->clone_and_inherit_options(%options);
+                    }
+                    else {
+                        # NOTE:
+                        # kind of a kludge to handle Class::MOP::Attributes
+                        $new_attr = Moose::Meta::Attribute::clone_and_inherit_options(
+                            $inherited_attr, %options
+                        );                        
+                    }
                     $meta->add_attribute($new_attr);
                 }
                 else {
@@ -108,46 +156,47 @@ use Moose::Util::TypeConstraints;
             };
         },
         before => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::before' => sub {
+            my $class = $CALLER;
+            return subname 'Moose::before' => sub (@&) {
                 my $code = pop @_;
+                my $meta = $class->meta;
                 $meta->add_before_method_modifier($_, $code) for @_;
             };
         },
         after => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::after' => sub {
+            my $class = $CALLER;
+            return subname 'Moose::after' => sub (@&) {
                 my $code = pop @_;
+                my $meta = $class->meta;
                 $meta->add_after_method_modifier($_, $code) for @_;
             };
         },
         around => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::around' => sub {
+            my $class = $CALLER;            
+            return subname 'Moose::around' => sub (@&) {
                 my $code = pop @_;
+                my $meta = $class->meta;
                 $meta->add_around_method_modifier($_, $code) for @_;
             };
         },
         super => sub {
-            my $meta = _find_meta();
             return subname 'Moose::super' => sub {};
         },
         override => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::override' => sub {
+            my $class = $CALLER;
+            return subname 'Moose::override' => sub ($&) {
                 my ($name, $method) = @_;
-                $meta->add_override_method_modifier($name => $method);
+                $class->meta->add_override_method_modifier($name => $method);
             };
         },
         inner => sub {
-            my $meta = _find_meta();
             return subname 'Moose::inner' => sub {};
         },
         augment => sub {
-            my $meta = _find_meta();
-            return subname 'Moose::augment' => sub {
+            my $class = $CALLER;
+            return subname 'Moose::augment' => sub (@&) {
                 my ($name, $method) = @_;
-                $meta->add_augment_method_modifier($name => $method);
+                $class->meta->add_augment_method_modifier($name => $method);
             };
         },
         confess => sub {
@@ -155,14 +204,6 @@ use Moose::Util::TypeConstraints;
         },
         blessed => sub {
             return \&Scalar::Util::blessed;
-        },
-        all_methods => sub {
-            subname 'Moose::all_methods' => sub () {
-                sub {
-                    my ( $class, $delegate_class ) = @_;
-                    $delegate_class->compute_all_applicable_methods();
-                }
-            }
         }
     );
 
@@ -175,10 +216,15 @@ use Moose::Util::TypeConstraints;
     
     sub import {     
         $CALLER = caller();
+        
+        strict->import;
+        warnings->import;        
 
         # we should never export to main
         return if $CALLER eq 'main';
-
+    
+        _init_meta();
+        
         goto $exporter;
     }
 }
@@ -220,10 +266,12 @@ Moose - Moose, it's the new Camel
 =head1 SYNOPSIS
 
   package Point;
+  use strict;
+  use warnings;
   use Moose;
        
-  has 'x' => (isa => 'Int', is => 'rw');
-  has 'y' => (isa => 'Int', is => 'rw');
+  has 'x' => (is => 'rw', isa => 'Int');
+  has 'y' => (is => 'rw', isa => 'Int');
   
   sub clear {
       my $self = shift;
@@ -232,23 +280,32 @@ Moose - Moose, it's the new Camel
   }
   
   package Point3D;
+  use strict;
+  use warnings;  
   use Moose;
   
   extends 'Point';
   
-  has 'z' => (isa => 'Int');
+  has 'z' => (is => 'rw', isa => 'Int');
   
   after 'clear' => sub {
       my $self = shift;
-      $self->{z} = 0;
+      $self->z(0);
   };
   
 =head1 CAVEAT
 
-This is an early release of this module, it still needs 
-some fine tuning and B<lots> more documentation. I am adopting 
-the I<release early and release often> approach with this module, 
-so keep an eye on your favorite CPAN mirror!
+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).  
+
+For more details, please refer to the L<FUTURE PLANS> section of 
+this document.
 
 =head1 DESCRIPTION
 
@@ -267,39 +324,26 @@ 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 What does Moose stand for??
+=head2 Can I use this in production? Or is this just an experiment?
 
-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 is I<based> on the prototypes and experiments I did for the Perl 6
+meta-model, however Moose is B<NOT> an experiment/prototype, it is 
+for B<real>. I will be deploying Moose into production environments later 
+this year, and I have all intentions of using it as my de-facto class 
+builderfrom now on. 
 
-=over 4
+=head2 Is Moose just Perl 6 in Perl 5?
 
-=item Make Other Object Systems Envious
-
-=item Makes Object Orientation So Easy
-
-=item Makes Object Orientation Spiffy- Er  (sorry ingy)
-
-=item Most Other Object Systems Emasculate
-
-=item My Overcraft Overfilled (with) Some Eels
-
-=item Moose Often Ovulate Sorta Early
-
-=item Many Overloaded Object Systems Exists 
-
-=item Moose Offers Often Super Extensions
-
-=item Meta Object Orientation Syntax Extensions
-
-=back
+No. While Moose is very much inspired by Perl 6, it is not. 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 :) 
 
 =head1 BUILDING CLASSES WITH MOOSE
 
 Moose makes every attempt to provide as much convience during class 
 construction/definition, but still stay out of your way if you want 
-it to. Here are some of the features Moose provides:
+it to. Here are a few items to note when building classes with Moose.
 
 Unless specified with C<extends>, any class which uses Moose will 
 inherit from L<Moose::Object>.
@@ -310,8 +354,6 @@ inherited from L<Moose::Object>, then this includes properly initializing
 all instance slots, setting defaults where approprtiate and performing any 
 type constraint checking or coercion. 
 
-For more details, see the ever expanding L<Moose::Cookbook>.
-
 =head1 EXPORTED FUNCTIONS
 
 Moose will export a number of functions into the class's namespace, which 
@@ -333,17 +375,17 @@ actually C<push>es onto the class's C<@ISA>, whereas C<extends> will
 replace it. This is important to ensure that classes which do not have 
 superclasses properly inherit from L<Moose::Object>.
 
-=item B<with ($role)>
+=item B<with (@roles)>
 
-This will apply a given C<$role> to the local class. Role support is 
-currently very experimental, see L<Moose::Role> for more details.
+This will apply a given set of C<@roles> to the local class. Role support 
+is currently under heavy development, see L<Moose::Role> for more details.
 
 =item B<has ($name, %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 both 
-L<Class::MOP::Attribute> and L<Moose::Meta::Attribute>, in addition to a 
-few convience ones provided by Moose which are listed below:
+The list of C<%options> are the same as those provided by 
+L<Class::MOP::Attribute>, in addition to the list below which are provided 
+by Moose (L<Moose::Meta::Attribute> to be more specific):
 
 =over 4
 
@@ -354,7 +396,7 @@ 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<reader>, I<writer> and I<accessor> options inherited from L<Moose::Meta::Attribute>.
+I<reader>, I<writer> and I<accessor> options inherited from L<Class::MOP::Attribute>.
 
 =item I<isa =E<gt> $type_name>
 
@@ -392,6 +434,11 @@ reference. If an attribute is a weakened reference, it can B<not> also be coerce
 This will tell the class to not create this slot until absolutely nessecary. 
 If an attribute is marked as lazy it B<must> have a default supplied.
 
+=item I<auto_deref =E<gt> (1|0)>
+
+This tells the accessor whether to automatically de-reference the value returned. 
+This is only legal if your C<isa> option is either an C<ArrayRef> or C<HashRef>.
+
 =item I<trigger =E<gt> $code>
 
 The trigger option is a CODE reference which will be called after the value of 
@@ -400,6 +447,11 @@ updated value and the attribute meta-object (this is for more advanced fiddling
 and can typically be ignored in most cases). You can B<not> have a trigger on 
 a read-only attribute.
 
+=item I<handles =E<gt> [ @handles ]>
+
+There is experimental support for attribute delegation using the C<handles> 
+option. More docs to come later.
+
 =back
 
 =item B<before $name|@names =E<gt> sub { ... }>
@@ -451,6 +503,49 @@ C<ref> anywhere you need to test for an object's class name.
 
 =back
 
+=head1 FUTURE PLANS
+
+Here is just a sampling of the plans we have in store for Moose:
+
+=over 4
+
+=item *
+
+Compiling Moose classes/roles into C<.pmc> files for faster loading and execution.
+
+=item * 
+
+Supporting sealed and finalized classes in Moose. This will allow greater control 
+of the extensions of frameworks and such.
+
+=back
+
+=head1 MISC.
+
+=head2 What does Moose stand for??
+
+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 :)
+
+=over 4
+
+=item Make Other Object Systems Envious
+
+=item Makes Object Orientation So Easy
+
+=item Makes Object Orientation Spiffy- Er  (sorry ingy)
+
+=item Most Other Object Systems Emasculate
+
+=item Moose Often Ovulate Sorta Early
+
+=item Moose Offers Often Super Extensions
+
+=item Meta Object Orientation Syntax Extensions
+
+=back
+
 =head1 CAVEATS
 
 =over 4
@@ -519,6 +614,10 @@ to cpan-RT.
 
 Stevan Little E<lt>stevan@iinteractive.comE<gt>
 
+Christian Hansen E<lt>chansen@cpan.orgE<gt>
+
+Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt>
+
 =head1 COPYRIGHT AND LICENSE
 
 Copyright 2006 by Infinity Interactive, Inc.