From: gfx Date: Mon, 22 Feb 2010 07:04:42 +0000 (+0900) Subject: Optimize Method::Delegation X-Git-Tag: 0.50_03~4 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=cb80a70a3d6101e0bc8f6576765a2d6c588d2ecd;p=gitmo%2FMouse.git Optimize Method::Delegation --- diff --git a/lib/Mouse/Meta/Method/Delegation.pm b/lib/Mouse/Meta/Method/Delegation.pm index 51e4999..60bdad8 100644 --- a/lib/Mouse/Meta/Method/Delegation.pm +++ b/lib/Mouse/Meta/Method/Delegation.pm @@ -3,26 +3,47 @@ use Mouse::Util qw(:meta); # enables strict and warnings use Scalar::Util; sub _generate_delegation{ - my (undef, $attribute, $handle_name, $method_to_call, @curried_args) = @_; - - my $reader = $attribute->get_read_method_ref(); - return sub { - my $instance = shift; - my $proxy = $instance->$reader(); - - my $error = !defined($proxy) ? ' is not defined' - : ref($proxy) && !Scalar::Util::blessed($proxy) ? qq{ is not an object (got '$proxy')} - : undef; - if ($error) { - $instance->meta->throw_error( - "Cannot delegate $handle_name to $method_to_call because " - . "the value of " - . $attribute->name - . $error - ); - } - $proxy->$method_to_call(@curried_args, @_); - }; + my (undef, $attr, $handle_name, $method_to_call, @curried_args) = @_; + + my $reader = $attr->get_read_method_ref(); + + my $can_be_optimized = $attr->{_method_delegation_can_be_optimized}; + + if(!defined $can_be_optimized){ + my $tc = $attr->type_constraint; + + $attr->{_method_delegation_can_be_optimized} = + (defined($tc) && $tc->is_a_type_of('Object')) + && ($attr->is_required || $attr->has_default || $attr->has_builder) + && ($attr->is_lazy || !$attr->has_clearer); + } + + if($can_be_optimized){ + # need not check the attribute value + return sub { + return shift()->$reader()->$method_to_call(@curried_args, @_); + }; + } + else { + # need to check the attribute value + return sub { + my $instance = shift; + my $proxy = $instance->$reader(); + + my $error = !defined($proxy) ? ' is not defined' + : ref($proxy) && !Scalar::Util::blessed($proxy) ? qq{ is not an object (got '$proxy')} + : undef; + if ($error) { + $instance->meta->throw_error( + "Cannot delegate $handle_name to $method_to_call because " + . "the value of " + . $attr->name + . $error + ); + } + $proxy->$method_to_call(@curried_args, @_); + }; + } } diff --git a/t/001_mouse/019-handles.t b/t/001_mouse/019-handles.t index 5bae5a9..3dbf314 100644 --- a/t/001_mouse/019-handles.t +++ b/t/001_mouse/019-handles.t @@ -1,21 +1,15 @@ #!/usr/bin/env perl use strict; use warnings; -use Test::More tests => 26; +use Test::More; use Test::Exception; do { package Person; + use Mouse; - sub new { - my $class = shift; - my %args = @_; - - bless \%args, $class; - } - - sub name { $_[0]->{name} = $_[1] if @_ > 1; $_[0]->{name} } - sub age { $_[0]->{age} = $_[1] if @_ > 1; $_[0]->{age} } + has name => (is => 'rw'); + has age => (is => 'rw'); sub make_string { my($self, $template) = @_; @@ -38,11 +32,13 @@ do { ); has me => ( - is => 'rw', + is => 'rw', + isa => 'Person', default => sub { Person->new(age => 21, name => "Shawn") }, predicate => 'quid', handles => [qw/name age/], ); + }; can_ok(Class => qw(person has_person person_name person_age name age quid)); @@ -85,29 +81,26 @@ is_deeply( "correct handles layout for 'person'", ); +throws_ok{ + $object->person(undef); + $object->person_name(); +} qr/Cannot delegate person_name to name because the value of person is not defined/; -{ - throws_ok{ - $object->person(undef); - $object->person_name(); - } qr/Cannot delegate person_name to name because the value of person is not defined/; - - throws_ok{ - $object->person([]); - $object->person_age(); - } qr/Cannot delegate person_age to age because the value of person is not an object/; -} +throws_ok{ + $object->person([]); + $object->person_age(); +} qr/Cannot delegate person_age to age because the value of person is not an object/; -eval{ +throws_ok{ $object->person(undef); $object->person_name(); -}; -like $@, qr/Cannot delegate person_name to name because the value of person is not defined/; +} qr/Cannot delegate person_name to name because the value of person is not defined/; -eval{ +throws_ok{ $object->person([]); $object->person_age(); -}; -like $@, qr/Cannot delegate person_age to age because the value of person is not an object/; +} qr/Cannot delegate person_age to age because the value of person is not an object/; + +done_testing;