Add $attribute->compute_all_accessors to ask attributes about their methods without... topic/attrs-satisfy-requires-in-composition
Florian Ragwitz [Sat, 6 Feb 2010 04:14:34 +0000 (05:14 +0100)]
lib/Class/MOP/Attribute.pm
t/014_attribute_introspection.t

index 6dffd9b..bf87737 100644 (file)
@@ -294,7 +294,7 @@ sub clear_value {
 
 sub accessor_metaclass { 'Class::MOP::Method::Accessor' }
 
-sub _process_accessors {
+sub _compute_accessors {
     my ($self, $type, $accessor, $generate_as_inline_methods) = @_;
 
     my $method_ctx;
@@ -307,69 +307,97 @@ sub _process_accessors {
         (ref($accessor) eq 'HASH')
             || confess "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref";
         my ($name, $method) = %{$accessor};
-        $method = $self->accessor_metaclass->wrap(
+        return ($name, [
+            $self->accessor_metaclass,
             $method,
-            package_name => $self->associated_class->name,
-            name         => $name,
+            name => $name,
             definition_context => $method_ctx,
-        );
-        $self->associate_method($method);
-        return ($name, $method);
+        ]);
     }
-    else {
-        my $inline_me = ($generate_as_inline_methods && $self->associated_class->instance_metaclass->is_inlinable);
-        my $method;
-        try {
-            if ( $method_ctx ) {
-                my $desc = "accessor $accessor";
-                if ( $accessor ne $self->name ) {
-                    $desc .= " of attribute " . $self->name;
-                }
-
-                $method_ctx->{description} = $desc;
-            }
-
-            $method = $self->accessor_metaclass->new(
-                attribute     => $self,
-                is_inline     => $inline_me,
-                accessor_type => $type,
-                package_name  => $self->associated_class->name,
-                name          => $accessor,
-                definition_context => $method_ctx,
-            );
+
+    my $inline_me = ($generate_as_inline_methods && $self->associated_class->instance_metaclass->is_inlinable);
+
+    if ( $method_ctx ) {
+        my $desc = "accessor $accessor";
+        if ( $accessor ne $self->name ) {
+            $desc .= " of attribute " . $self->name;
         }
-        catch {
-            confess "Could not create the '$type' method for " . $self->name . " because : $_";
-        };
-        $self->associate_method($method);
-        return ($accessor, $method);
+
+        $method_ctx->{description} = $desc;
     }
+
+    return ($accessor, [
+        $self->accessor_metaclass,
+        attribute     => $self,
+        is_inline     => $inline_me,
+        accessor_type => $type,
+        name          => $accessor,
+        definition_context => $method_ctx,
+    ]);
+}
+
+sub _create_accessors {
+    my ($self, $type, $args) = @_;
+
+    my $accessor_metaclass = shift @{ $args };
+    my $create = (ref $args->[0] && ref $args->[0] eq 'CODE') ? 'wrap' : 'new';
+
+    my $method;
+    try {
+        $method = $accessor_metaclass->$create(
+            @{ $args }, package_name => $self->associated_class->name,
+        );
+    }
+    catch {
+        confess "Could not create the '$type' method for " . $self->name . " because : $_";
+    };
+
+    $self->associate_method($method);
+
+    return $method;
+}
+
+# for extension compatibility
+sub _process_accessors {
+    my $self = shift;
+    my ($type, $accessor, $generate_as_inline_methods) = @_;
+
+    my ($name, $args) = $self->_compute_accessors(@_);
+    my $method = $self->_create_accessors($type, $args);
+
+    return ($name, $method);
+}
+
+sub compute_all_accessors {
+    my ($self, $inline) = @_;
+
+    my @ret = map {
+        $self->${\"has_$_"}
+            ? ($_ => [$self->_compute_accessors($_ => $self->$_, $inline)])
+            : ()
+    } qw(accessor reader writer predicate clearer);
+
+    return @ret;
 }
 
 sub install_accessors {
     my $self   = shift;
     my $inline = shift;
-    my $class  = $self->associated_class;
-
-    $class->add_method(
-        $self->_process_accessors('accessor' => $self->accessor(), $inline)
-    ) if $self->has_accessor();
 
-    $class->add_method(
-        $self->_process_accessors('reader' => $self->reader(), $inline)
-    ) if $self->has_reader();
+    my %accessors = $self->compute_all_accessors($inline);
+    while (my ($type, $desc) = each %accessors) {
+        my ($name, $args) = @{ $desc };
+        $self->_install_accessor($name => $self->_create_accessors($type => $args));
+    }
 
-    $class->add_method(
-        $self->_process_accessors('writer' => $self->writer(), $inline)
-    ) if $self->has_writer();
+    return;
+}
 
-    $class->add_method(
-        $self->_process_accessors('predicate' => $self->predicate(), $inline)
-    ) if $self->has_predicate();
+sub _install_accessor {
+    my ($self, $name, $method) = @_;
+    my $class  = $self->associated_class;
 
-    $class->add_method(
-        $self->_process_accessors('clearer' => $self->clearer(), $inline)
-    ) if $self->has_clearer();
+    $class->add_method($name => $method);
 
     return;
 }
index 25d52c6..37458fb 100644 (file)
@@ -59,7 +59,11 @@ use Class::MOP;
 
         process_accessors
         _process_accessors
+        compute_all_accessors
+        _compute_accessors
         install_accessors
+        _create_accessors
+        _install_accessor
         remove_accessors
 
         _new