ChangeLog and adding yuval to authors everywhere
[gitmo/Class-MOP.git] / lib / Class / MOP.pm
index ce1b6e6..af04c94 100644 (file)
@@ -4,15 +4,199 @@ 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;
+
+use Class::MOP::Class::Immutable;
+
+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 
+## ----------------------------------------------------------------------------
+## The code below here is to bootstrap our MOP with itself. This is also 
+## sometimes called "tying the knot". By doing this, we make it much easier
+## to extend the MOP through subclassing and such since now you can use the
+## MOP itself to extend itself. 
+## 
+## Yes, I know, thats weird and insane, but it's a good thing, trust me :)
+## ---------------------------------------------------------------------------- 
+
+# We need to add in the meta-attributes here so that 
+# 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('%: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('$: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' => (
+        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
+# it will "tie the knot" with Class::MOP::Attribute
+# so that it uses the attributes meta-objects 
+# to construct itself. 
+Class::MOP::Attribute->meta->add_method('new' => sub {
+    my $class   = shift;
+    my $name    = shift;
+    my %options = @_;    
+        
+    (defined $name && $name)
+        || confess "You must provide a name for the attribute";
+    $options{init_arg} = $name 
+        if not exists $options{init_arg};
+
+    # return the new object
+    $class->meta->new_object(name => $name, %options);
+});
+
+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);
 
-our $VERSION = '0.01';
-
-# my %METAS;
-# sub UNIVERSAL::meta { 
-#     my $class = blessed($_[0]) || $_[0];
-#     $METAS{$class} ||= Class::MOP::Class->initialize($class) 
-# }
 
 1;
 
@@ -26,7 +210,8 @@ Class::MOP - A Meta Object Protocol for Perl 5
 
 =head1 SYNOPSIS
 
-  # ... coming soon
+  # ... This will come later, for now see
+  # the other SYNOPSIS for more information
 
 =head1 DESCRIPTON
 
@@ -40,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. 
@@ -77,16 +268,18 @@ 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. So many of 
-it's features are accessible without B<any> change to your existsing 
+This module was designed to be as unintrusive as possible. Many of 
+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.
+not an intrusion on your code base. Unlike many other B<Class::> 
+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 feature which requires additions to your code are the 
-attribute handling and instance construction 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.
+The only features which requires additions to your code are the 
+attribute handling and instance construction features, and these are
+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.
 
 =head2 A Note about Performance?
 
@@ -101,9 +294,52 @@ designed into the language and runtime (the CLR). In contrast, CLOS
 and so performance is tuned for it. 
 
 This library in particular does it's absolute best to avoid putting 
-B<any> drain at all upon your code's performance, while still trying 
-to make sure it is fast as well (although only as a secondary 
-concern).
+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
 
@@ -144,19 +380,51 @@ 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"
 
 =item "Advances in Object-Oriented Metalevel Architecture and Reflection"
 
+=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
 
@@ -168,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