my $names = shift;
$names = [$names] if !ref($names);
+ my $metaclass = 'Mouse::Meta::Attribute';
+ my %options = @_;
+
+ if ( my $metaclass_name = delete $options{metaclass} ) {
+ my $new_class = Mouse::Util::resolve_metaclass_alias(
+ 'Attribute',
+ $metaclass_name
+ );
+ if ( $metaclass ne $new_class ) {
+ $metaclass = $new_class;
+ }
+ }
for my $name (@$names) {
if ($name =~ s/^\+//) {
- Mouse::Meta::Attribute->clone_parent($meta, $name, @_);
+ $metaclass->clone_parent($meta, $name, @_);
}
else {
- Mouse::Meta::Attribute->create($meta, $name, @_);
+ $metaclass->create($meta, $name, @_);
}
}
}
*{ __PACKAGE__ . '::get_linear_isa'} = $impl;
}
+# taken from Class/MOP.pm
+{
+ my %cache;
+
+ sub resolve_metaclass_alias {
+ my ( $type, $metaclass_name, %options ) = @_;
+
+ my $cache_key = $type;
+ return $cache{$cache_key}{$metaclass_name}
+ if $cache{$cache_key}{$metaclass_name};
+
+ my $possible_full_name =
+ 'Mouse::Meta::'
+ . $type
+ . '::Custom::'
+ . $metaclass_name;
+
+ my $loaded_class =
+ load_first_existing_class( $possible_full_name,
+ $metaclass_name );
+
+ return $cache{$cache_key}{$metaclass_name} =
+ $loaded_class->can('register_implementation')
+ ? $loaded_class->register_implementation
+ : $loaded_class;
+ }
+}
+
+# taken from Class/MOP.pm
+sub _is_valid_class_name {
+ my $class = shift;
+
+ return 0 if ref($class);
+ return 0 unless defined($class);
+ return 0 unless length($class);
+
+ return 1 if $class =~ /^\w+(?:::\w+)*$/;
+
+ return 0;
+}
+
+# taken from Class/MOP.pm
+sub load_first_existing_class {
+ my @classes = @_
+ or return;
+
+ foreach my $class (@classes) {
+ unless ( _is_valid_class_name($class) ) {
+ my $display = defined($class) ? $class : 'undef';
+ confess "Invalid class name ($display)";
+ }
+ }
+
+ my $found;
+ my %exceptions;
+ for my $class (@classes) {
+ my $e = _try_load_one_class($class);
+
+ if ($e) {
+ $exceptions{$class} = $e;
+ }
+ else {
+ $found = $class;
+ last;
+ }
+ }
+ return $found if $found;
+
+ confess join(
+ "\n",
+ map {
+ sprintf( "Could not load class (%s) because : %s",
+ $_, $exceptions{$_} )
+ } @classes
+ );
+}
+
+# taken from Class/MOP.pm
+sub _try_load_one_class {
+ my $class = shift;
+
+ return if Mouse::is_class_loaded($class);
+
+ my $file = $class . '.pm';
+ $file =~ s{::}{/}g;
+
+ return do {
+ local $@;
+ eval { require($file) };
+ $@;
+ };
+}
+
sub apply_all_roles {
my $meta = Mouse::Meta::Class->initialize(shift);
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More tests => 2;
+use lib 't/lib';
+
+do {
+ package MouseX::AttributeHelpers::Number;
+ use Mouse;
+ extends 'Mouse::Meta::Attribute';
+
+ around 'create' => sub {
+ my ($next, @args) = @_;
+ my $attr = $next->(@args);
+ my %provides = %{$attr->{provides}};
+ my $method_constructors = {
+ add => sub {
+ my ($attr, $name) = @_;
+ return sub {
+ $_[0]->$name( $_[0]->$name() + $_[1])
+ };
+ },
+ };
+ while (my ($name, $aliased) = each %provides) {
+ $attr->associated_class->add_method(
+ $aliased => $method_constructors->{$name}->($attr, $attr->name)
+ );
+ }
+ return $attr;
+ };
+
+ package # hide me from search.cpan.org
+ Mouse::Meta::Attribute::Custom::Number;
+ sub register_implementation { 'MouseX::AttributeHelpers::Number' }
+
+ 1;
+
+ package Klass;
+ use Mouse;
+
+ has 'i' => (
+ metaclass => 'Number',
+ is => 'rw',
+ isa => 'Int',
+ provides => {
+ 'add' => 'add_number'
+ },
+ );
+};
+
+can_ok 'Klass', 'add_number';
+my $k = Klass->new(i=>3);
+$k->add_number(4);
+is $k->i, 7;
+