ChangeLog and adding yuval to authors everywhere
[gitmo/Class-MOP.git] / lib / Class / MOP.pm
index 0a650dc..af04c94 100644 (file)
@@ -4,24 +4,25 @@ package Class::MOP;
 use strict;
 use warnings;
 
-use Scalar::Util 'blessed';
 use Carp         'confess';
+use Scalar::Util ();
 
 use Class::MOP::Class;
 use Class::MOP::Attribute;
 use Class::MOP::Method;
 
-our $VERSION = '0.01';
+use Class::MOP::Class::Immutable;
 
-sub import {
-    shift;
-    return unless @_;
-    if ($_[0] eq ':universal') {
-        *UNIVERSAL::meta = sub { 
-            Class::MOP::Class->initialize(blessed($_[0]) || $_[0]) 
-        };
-    }
-}
+our $VERSION = '0.31';
+
+## ----------------------------------------------------------------------------
+## Setting up our environment ...
+## ----------------------------------------------------------------------------
+## Class::MOP needs to have a few things in the global perl environment so 
+## that it can operate effectively. Those things are done here.
+## ----------------------------------------------------------------------------
+
+# ... nothing yet actually ;)
 
 ## ----------------------------------------------------------------------------
 ## Bootstrapping 
@@ -38,30 +39,130 @@ sub import {
 # any subclass of Class::MOP::* will be able to 
 # inherit them using &construct_instance
 
+## Class::MOP::Package
+
+Class::MOP::Package->meta->add_attribute(
+    Class::MOP::Attribute->new('$:package' => (
+        reader   => {
+            # NOTE: we need to do this in order 
+            # for the instance meta-object to 
+            # not fall into meta-circular death
+            'name' => sub { (shift)->{'$:package'} }
+        },
+        init_arg => ':package',
+    ))
+);
+
 ## Class::MOP::Class
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('$:pkg' => (
-        init_arg => ':pkg'
+    Class::MOP::Attribute->new('%:attributes' => (
+        reader   => {
+            # NOTE: we need to do this in order 
+            # for the instance meta-object to 
+            # not fall into meta-circular death            
+            'get_attribute_map' => sub { (shift)->{'%:attributes'} }
+        },
+        init_arg => ':attributes',
+        default  => sub { {} }
     ))
 );
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('%:attrs' => (
-        init_arg => ':attrs',
-        default  => sub { {} }
+    Class::MOP::Attribute->new('$:attribute_metaclass' => (
+        reader   => 'attribute_metaclass',
+        init_arg => ':attribute_metaclass',
+        default  => 'Class::MOP::Attribute',
+    ))
+);
+
+Class::MOP::Class->meta->add_attribute(
+    Class::MOP::Attribute->new('$:method_metaclass' => (
+        reader   => 'method_metaclass',
+        init_arg => ':method_metaclass',
+        default  => 'Class::MOP::Method',        
+    ))
+);
+
+Class::MOP::Class->meta->add_attribute(
+    Class::MOP::Attribute->new('$:instance_metaclass' => (
+        reader   => {
+            # NOTE: we need to do this in order 
+            # for the instance meta-object to 
+            # not fall into meta-circular death            
+            'instance_metaclass' => sub { (shift)->{'$:instance_metaclass'} }
+        },
+        init_arg => ':instance_metaclass',
+        default  => 'Class::MOP::Instance',        
     ))
 );
 
 ## Class::MOP::Attribute
 
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('name'));
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('accessor'));
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('reader'));
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('writer'));
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('predicate'));
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('init_arg'));
-Class::MOP::Attribute->meta->add_attribute(Class::MOP::Attribute->new('default'));
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('name' => (
+        reader => {
+            # NOTE: we need to do this in order 
+            # for the instance meta-object to 
+            # not fall into meta-circular death            
+            'name' => sub { (shift)->{name} }
+        }
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('associated_class' => (
+        reader => {
+            # NOTE: we need to do this in order 
+            # for the instance meta-object to 
+            # not fall into meta-circular death            
+            'associated_class' => sub { (shift)->{associated_class} }
+        }
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('accessor' => (
+        reader    => 'accessor',
+        predicate => 'has_accessor',
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('reader' => (
+        reader    => 'reader',
+        predicate => 'has_reader',
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('writer' => (
+        reader    => 'writer',
+        predicate => 'has_writer',
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('predicate' => (
+        reader    => 'predicate',
+        predicate => 'has_predicate',
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('init_arg' => (
+        reader    => 'init_arg',
+        predicate => 'has_init_arg',
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('default' => (
+        # default has a custom 'reader' method ...
+        predicate => 'has_default',
+    ))
+);
+
 
 # NOTE: (meta-circularity)
 # This should be one of the last things done
@@ -75,25 +176,28 @@ Class::MOP::Attribute->meta->add_method('new' => sub {
         
     (defined $name && $name)
         || confess "You must provide a name for the attribute";
-    (!exists $options{reader} && !exists $options{writer})
-        || confess "You cannot declare an accessor and reader and/or writer functions"
-            if exists $options{accessor};
-            
-    bless $class->meta->construct_instance(name => $name, %options) => $class;
+    $options{init_arg} = $name 
+        if not exists $options{init_arg};
+
+    # return the new object
+    $class->meta->new_object(name => $name, %options);
 });
 
-# NOTE: (meta-circularity)
-# This is how we "tie the knot" for the class
-# meta-objects. This is used to construct the
-# Class::MOP::Class instances after all the 
-# bootstrapping is complete.
-Class::MOP::Class->meta->add_method('construct_class_instance' => sub {
-    my ($class, $package_name) = @_;
-    (defined $package_name && $package_name)
-        || confess "You must pass a package name";      
-    bless Class::MOP::Class->meta->construct_instance(':pkg' => $package_name) => blessed($class) || $class        
+Class::MOP::Attribute->meta->add_method('clone' => sub {
+    my $self  = shift;
+    $self->meta->clone_object($self, @_);  
 });
 
+## Try and close Class::MOP::*
+
+Class::MOP::Package  ->meta->make_immutable(inline_constructor => 0);
+Class::MOP::Module   ->meta->make_immutable(inline_constructor => 0);
+Class::MOP::Class    ->meta->make_immutable(inline_constructor => 0);
+Class::MOP::Attribute->meta->make_immutable(inline_constructor => 0);
+Class::MOP::Method   ->meta->make_immutable(inline_constructor => 0);
+Class::MOP::Instance ->meta->make_immutable(inline_constructor => 0);
+
+
 1;
 
 __END__
@@ -106,11 +210,8 @@ Class::MOP - A Meta Object Protocol for Perl 5
 
 =head1 SYNOPSIS
 
-  use Class::MOP ':universal';
-  
-  package Foo;
-  
-  Foo->meta->add_method('foo' => sub { ... });
+  # ... This will come later, for now see
+  # the other SYNOPSIS for more information
 
 =head1 DESCRIPTON
 
@@ -124,6 +225,12 @@ set of extensions to the Perl 5 object system. Every attempt has been
 made for these tools to keep to the spirit of the Perl 5 object 
 system that we all know and love.
 
+This documentation is admittedly sparse on details, as time permits 
+I will try to improve them. For now, I suggest looking at the items 
+listed in the L<SEE ALSO> section for more information. In particular 
+the book "The Art of the Meta Object Protocol" was very influential 
+in the development of this system.
+
 =head2 What is a Meta Object Protocol?
 
 A meta object protocol is an API to an object system. 
@@ -162,15 +269,15 @@ of method dispatch.
 =head2 What changes do I have to make to use this module?
 
 This module was designed to be as unintrusive as possible. Many of 
-it's features are accessible without B<any> change to your existsing 
+its features are accessible without B<any> change to your existsing 
 code at all. It is meant to be a compliment to your existing code and 
 not an intrusion on your code base. Unlike many other B<Class::> 
-modules, this module does require you subclass it, or even that you 
-C<use> it in within your module's package. 
+modules, this module B<does not> require you subclass it, or even that 
+you C<use> it in within your module's package. 
 
 The only features which requires additions to your code are the 
 attribute handling and instance construction features, and these are
-both optional features as well. The only reason for this is because 
+both completely optional features. The only reason for this is because 
 Perl 5's object system does not actually have these features built 
 in. More information about this feature can be found below.
 
@@ -191,6 +298,49 @@ B<any> drain at all upon your code's performance. In fact, by itself
 it does nothing to affect your existing code. So you only pay for 
 what you actually use.
 
+=head2 About Metaclass compatibility
+
+This module makes sure that all metaclasses created are both upwards 
+and downwards compatible. The topic of metaclass compatibility is 
+highly esoteric and is something only encountered when doing deep and 
+involved metaclass hacking. There are two basic kinds of metaclass 
+incompatibility; upwards and downwards. 
+
+Upwards metaclass compatibility means that the metaclass of a 
+given class is either the same as (or a subclass of) all of the 
+class's ancestors.
+
+Downward metaclass compatibility means that the metaclasses of a 
+given class's anscestors are all either the same as (or a subclass 
+of) that metaclass.
+
+Here is a diagram showing a set of two classes (C<A> and C<B>) and 
+two metaclasses (C<Meta::A> and C<Meta::B>) which have correct  
+metaclass compatibility both upwards and downwards.
+
+    +---------+     +---------+
+    | Meta::A |<----| Meta::B |      <....... (instance of  )
+    +---------+     +---------+      <------- (inherits from)  
+         ^               ^
+         :               :
+    +---------+     +---------+
+    |    A    |<----|    B    |
+    +---------+     +---------+
+
+As I said this is a highly esoteric topic and one you will only run 
+into if you do a lot of subclassing of B<Class::MOP::Class>. If you 
+are interested in why this is an issue see the paper 
+I<Uniform and safe metaclass composition> linked to in the 
+L<SEE ALSO> section of this document.
+
+=head2 Using custom metaclasses
+
+Always use the metaclass pragma when using a custom metaclass, this 
+will ensure the proper initialization order and not accidentely 
+create an incorrect type of metaclass for you. This is a very rare 
+problem, and one which can only occur if you are doing deep metaclass 
+programming. So in other words, don't worry about it.
+
 =head1 PROTOCOLS
 
 The protocol is divided into 3 main sub-protocols:
@@ -230,6 +380,11 @@ See L<Class::MOP::Method> for more details.
 
 =head2 Books
 
+There are very few books out on Meta Object Protocols and Metaclasses 
+because it is such an esoteric topic. The following books are really 
+the only ones I have found. If you know of any more, B<I<please>> 
+email me and let me know, I would love to hear about them.
+
 =over 4
 
 =item "The Art of the Meta Object Protocol"
@@ -238,13 +393,38 @@ See L<Class::MOP::Method> for more details.
 
 =item "Putting MetaClasses to Work"
 
+=item "Smalltalk: The Language"
+
+=back
+
+=head2 Papers
+
+=over 4
+
+=item Uniform and safe metaclass composition
+
+An excellent paper by the people who brought us the original Traits paper. 
+This paper is on how Traits can be used to do safe metaclass composition, 
+and offers an excellent introduction section which delves into the topic of 
+metaclass compatibility.
+
+L<http://www.iam.unibe.ch/~scg/Archive/Papers/Duca05ySafeMetaclassTrait.pdf>
+
+=item Safe Metaclass Programming
+
+This paper seems to precede the above paper, and propose a mix-in based 
+approach as opposed to the Traits based approach. Both papers have similar 
+information on the metaclass compatibility problem space. 
+
+L<http://citeseer.ist.psu.edu/37617.html>
+
 =back
 
 =head2 Prior Art
 
 =over 4
 
-=item The Perl 6 MetaModel work
+=item The Perl 6 MetaModel work in the Pugs project
 
 =over 4
 
@@ -256,11 +436,54 @@ See L<Class::MOP::Method> for more details.
 
 =back
 
-=head1 AUTHOR
+=head1 SIMILAR MODULES
+
+As I have said above, this module is a class-builder-builder, so it is 
+not the same thing as modules like L<Class::Accessor> and 
+L<Class::MethodMaker>. That being said there are very few modules on CPAN 
+with similar goals to this module. The one I have found which is most 
+like this module is L<Class::Meta>, although it's philosophy and the MOP it 
+creates are very different from this modules. 
+
+=head1 BUGS
+
+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 CODE COVERAGE
+
+I use L<Devel::Cover> to test the code coverage of my tests, below is the 
+L<Devel::Cover> report on this module's test suite.
+
+ ---------------------------- ------ ------ ------ ------ ------ ------ ------
+ File                           stmt   bran   cond    sub    pod   time  total
+ ---------------------------- ------ ------ ------ ------ ------ ------ ------
+ Class/MOP.pm                  100.0  100.0  100.0  100.0    n/a   19.8  100.0
+ Class/MOP/Attribute.pm        100.0  100.0   91.7   61.2  100.0   14.3   87.9
+ Class/MOP/Class.pm             97.6   91.3   77.3   98.4  100.0   56.4   93.2
+ Class/MOP/Instance.pm          91.1   75.0   33.3   91.7  100.0    6.8   90.7
+ Class/MOP/Method.pm            97.6   60.0   52.9   76.9  100.0    1.6   82.6
+ metaclass.pm                  100.0  100.0   83.3  100.0    n/a    1.0   97.7
+ ---------------------------- ------ ------ ------ ------ ------ ------ ------
+ Total                          97.5   88.5   75.5   82.8  100.0  100.0   91.2
+ ---------------------------- ------ ------ ------ ------ ------ ------ ------
+
+=head1 ACKNOWLEDGEMENTS
+
+=over 4
+
+=item Rob Kinyon E<lt>rob@iinteractive.comE<gt>
+
+Thanks to Rob for actually getting the development of this module kick-started. 
+
+=back
+
+=head1 AUTHORS
 
-Stevan Little E<gt>stevan@iinteractive.comE<lt>
+Stevan Little E<lt>stevan@iinteractive.comE<gt>
 
-Rob Kinyon E<gt>rob@iinteractive.comE<lt>
+Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
 
 =head1 COPYRIGHT AND LICENSE