Move method modifier manipulators into XS
[gitmo/Mouse.git] / lib / Mouse / PurePerl.pm
index df00604..31e4a12 100644 (file)
@@ -2,8 +2,7 @@ package Mouse::PurePerl;
 
 require Mouse::Util;
 
-package
-    Mouse::Util;
+package Mouse::Util;
 
 use strict;
 use warnings;
@@ -12,6 +11,19 @@ use warnings FATAL => 'redefine'; # to avoid to load Mouse::PurePerl
 
 use B ();
 
+
+# taken from Class/MOP.pm
+sub is_valid_class_name {
+    my $class = shift;
+
+    return 0 if ref($class);
+    return 0 unless defined($class);
+
+    return 1 if $class =~ /\A \w+ (?: :: \w+ )* \z/xms;
+
+    return 0;
+}
+
 sub is_class_loaded {
     my $class = shift;
 
@@ -124,8 +136,7 @@ sub generate_can_predicate_for {
     return $predicate;
 }
 
-package
-    Mouse::Util::TypeConstraints;
+package Mouse::Util::TypeConstraints;
 
 use Scalar::Util qw(blessed looks_like_number openhandle);
 
@@ -195,12 +206,9 @@ sub _parameterize_Maybe_for {
     return sub{
         return !defined($_) || $check->($_);
     };
-};
-
-
+}
 
-package
-    Mouse::Meta::Module;
+package Mouse::Meta::Module;
 
 sub name          { $_[0]->{package} }
 
@@ -236,8 +244,7 @@ sub add_method {
     return;
 }
 
-package
-    Mouse::Meta::Class;
+package Mouse::Meta::Class;
 
 sub method_metaclass    { $_[0]->{method_metaclass}    || 'Mouse::Meta::Method'    }
 sub attribute_metaclass { $_[0]->{attribute_metaclass} || 'Mouse::Meta::Attribute' }
@@ -325,8 +332,9 @@ sub _initialize_object{
 
 sub is_immutable {  $_[0]->{is_immutable} }
 
-package
-    Mouse::Meta::Role;
+sub __strict_constructor{ $_[0]->{strict_constructor} }
+
+package Mouse::Meta::Role;
 
 sub method_metaclass{ $_[0]->{method_metaclass} || 'Mouse::Meta::Role::Method' }
 
@@ -336,8 +344,39 @@ sub is_anon_role{
 
 sub get_roles { $_[0]->{roles} }
 
-package
-    Mouse::Meta::Attribute;
+sub add_before_method_modifier {
+    my ($self, $method_name, $method) = @_;
+
+    push @{ $self->{before_method_modifiers}{$method_name} ||= [] }, $method;
+    return;
+}
+sub add_around_method_modifier {
+    my ($self, $method_name, $method) = @_;
+
+    push @{ $self->{around_method_modifiers}{$method_name} ||= [] }, $method;
+    return;
+}
+sub add_after_method_modifier {
+    my ($self, $method_name, $method) = @_;
+
+    push @{ $self->{after_method_modifiers}{$method_name} ||= [] }, $method;
+    return;
+}
+
+sub get_before_method_modifiers {
+    my ($self, $method_name) = @_;
+    return @{ $self->{before_method_modifiers}{$method_name} ||= [] }
+}
+sub get_around_method_modifiers {
+    my ($self, $method_name) = @_;
+    return @{ $self->{around_method_modifiers}{$method_name} ||= [] }
+}
+sub get_after_method_modifiers {
+    my ($self, $method_name) = @_;
+    return @{ $self->{after_method_modifiers}{$method_name} ||= [] }
+}
+
+package Mouse::Meta::Attribute;
 
 require Mouse::Meta::Method::Accessor;
 
@@ -387,18 +426,146 @@ sub has_builder          { exists $_[0]->{builder}         }
 
 sub has_documentation    { exists $_[0]->{documentation}   }
 
-package
-    Mouse::Meta::TypeConstraint;
+sub _process_options{
+    my($class, $name, $args) = @_;
+
+    # taken from Class::MOP::Attribute::new
+
+    defined($name)
+        or $class->throw_error('You must provide a name for the attribute');
+
+    if(!exists $args->{init_arg}){
+        $args->{init_arg} = $name;
+    }
+
+    # 'required' requires eigher 'init_arg', 'builder', or 'default'
+    my $can_be_required = defined( $args->{init_arg} );
+
+    if(exists $args->{builder}){
+        # XXX:
+        # Moose refuses a CODE ref builder, but Mouse doesn't for backward compatibility
+        # This feature will be changed in a future. (gfx)
+        $class->throw_error('builder must be a defined scalar value which is a method name')
+            #if ref $args->{builder} || !defined $args->{builder};
+            if !defined $args->{builder};
+
+        $can_be_required++;
+    }
+    elsif(exists $args->{default}){
+        if(ref $args->{default} && ref($args->{default}) ne 'CODE'){
+            $class->throw_error("References are not allowed as default values, you must "
+                              . "wrap the default of '$name' in a CODE reference (ex: sub { [] } and not [])");
+        }
+        $can_be_required++;
+    }
+
+    if( $args->{required} && !$can_be_required ) {
+        $class->throw_error("You cannot have a required attribute ($name) without a default, builder, or an init_arg");
+    }
+
+    # taken from Mouse::Meta::Attribute->new and ->_process_args
+
+    if(exists $args->{is}){
+        my $is = $args->{is};
+
+        if($is eq 'ro'){
+            $args->{reader} ||= $name;
+        }
+        elsif($is eq 'rw'){
+            if(exists $args->{writer}){
+                $args->{reader} ||= $name;
+             }
+             else{
+                $args->{accessor} ||= $name;
+             }
+        }
+        elsif($is eq 'bare'){
+            # do nothing, but don't complain (later) about missing methods
+        }
+        else{
+            $is = 'undef' if !defined $is;
+            $class->throw_error("I do not understand this option (is => $is) on attribute ($name)");
+        }
+    }
+
+    my $tc;
+    if(exists $args->{isa}){
+        $tc = $args->{type_constraint} = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($args->{isa});
+    }
+
+    if(exists $args->{does}){
+        if(defined $tc){ # both isa and does supplied
+            my $does_ok = do{
+                local $@;
+                eval{ "$tc"->does($args) };
+            };
+            if(!$does_ok){
+                $class->throw_error("Cannot have both an isa option and a does option because '$tc' does not do '$args->{does}' on attribute ($name)");
+            }
+        }
+        else {
+            $tc = $args->{type_constraint} = Mouse::Util::TypeConstraints::find_or_create_does_type_constraint($args->{does});
+        }
+    }
+
+    if($args->{coerce}){
+        defined($tc)
+            || $class->throw_error("You cannot have coercion without specifying a type constraint on attribute ($name)");
+
+        $args->{weak_ref}
+            && $class->throw_error("You cannot have a weak reference to a coerced value on attribute ($name)");
+    }
+
+    if ($args->{lazy_build}) {
+        exists($args->{default})
+            && $class->throw_error("You can not use lazy_build and default for the same attribute ($name)");
+
+        $args->{lazy}      = 1;
+        $args->{builder} ||= "_build_${name}";
+        if ($name =~ /^_/) {
+            $args->{clearer}   ||= "_clear${name}";
+            $args->{predicate} ||= "_has${name}";
+        }
+        else {
+            $args->{clearer}   ||= "clear_${name}";
+            $args->{predicate} ||= "has_${name}";
+        }
+    }
+
+    if ($args->{auto_deref}) {
+        defined($tc)
+            || $class->throw_error("You cannot auto-dereference without specifying a type constraint on attribute ($name)");
+
+        ( $tc->is_a_type_of('ArrayRef') || $tc->is_a_type_of('HashRef') )
+            || $class->throw_error("You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)");
+    }
+
+    if (exists $args->{trigger}) {
+        ('CODE' eq ref $args->{trigger})
+            || $class->throw_error("Trigger must be a CODE ref on attribute ($name)");
+    }
+
+    if ($args->{lazy}) {
+        (exists $args->{default} || defined $args->{builder})
+            || $class->throw_error("You cannot have lazy attribute ($name) without specifying a default value for it");
+    }
+
+    return;
+}
+
+
+package Mouse::Meta::TypeConstraint;
 
 sub name    { $_[0]->{name}    }
 sub parent  { $_[0]->{parent}  }
 sub message { $_[0]->{message} }
 
+sub type_parameter           { $_[0]->{type_parameter} }
 sub _compiled_type_constraint{ $_[0]->{compiled_type_constraint} }
-
 sub _compiled_type_coercion  { $_[0]->{_compiled_type_coercion}  }
 
-sub has_coercion{ exists $_[0]->{_compiled_type_coercion} }
+sub __is_parameterized { exists $_[0]->{type_parameter} }
+sub has_coercion {       exists $_[0]->{_compiled_type_coercion} }
 
 
 sub compile_type_constraint{
@@ -447,9 +614,7 @@ sub compile_type_constraint{
     return;
 }
 
-package
-    Mouse::Object;
-
+package Mouse::Object;
 
 sub BUILDARGS {
     my $class = shift;
@@ -498,7 +663,6 @@ sub DESTROY {
     my $e = do{
         local $@;
         eval{
-
             # DEMOLISHALL
 
             # We cannot count on being able to retrieve a previously made
@@ -510,7 +674,7 @@ sub DESTROY {
                 my $demolish = Mouse::Util::get_code_ref($class, 'DEMOLISH')
                     || next;
 
-                $self->$demolish();
+                $self->$demolish($Mouse::Util::in_global_destruction);
             }
         };
         $@;
@@ -547,7 +711,7 @@ Mouse::PurePerl - A Mouse guts in pure Perl
 
 =head1 VERSION
 
-This document describes Mouse version 0.4501
+This document describes Mouse version 0.50_03
 
 =head1 SEE ALSO