use strict;
use warnings;
-use Test::More tests => 54;
+use Test::More tests => 88;
use Test::Exception;
-BEGIN {
- use_ok('Moose');
-}
+
+# -------------------------------------------------------------------
+# HASH handles
+# -------------------------------------------------------------------
# the canonical form of of the 'handles'
-# option is the hash ref mapping a
+# option is the hash ref mapping a
# method name to the delegated method name
{
package Foo;
use Moose;
- has 'bar' => (is => 'rw', default => 10);
+ has 'bar' => (is => 'rw', default => 10);
package Bar;
- use Moose;
-
+ use Moose;
+
has 'foo' => (
is => 'rw',
default => sub { Foo->new },
ok($bar->foo, '... we have something in bar->foo');
isa_ok($bar->foo, 'Foo');
+my $meth = Bar->meta->get_method('foo_bar');
+isa_ok($meth, 'Moose::Meta::Method::Delegation');
+is($meth->associated_attribute->name, 'foo',
+ 'associated_attribute->name for this method is foo');
+
is($bar->foo->bar, 10, '... bar->foo->bar returned the right default');
can_ok($bar, 'foo_bar');
is($bar->foo_bar, 10, '... bar->foo_bar delegated correctly');
+# change the value ...
+
+$bar->foo->bar(30);
+
+# and make sure the delegation picks it up
+
+is($bar->foo->bar, 30, '... bar->foo->bar returned the right (changed) value');
+is($bar->foo_bar, 30, '... bar->foo_bar delegated correctly');
+
+# change the value through the delegation ...
+
+$bar->foo_bar(50);
+
+# and make sure everyone sees it
+
+is($bar->foo->bar, 50, '... bar->foo->bar returned the right (changed) value');
+is($bar->foo_bar, 50, '... bar->foo_bar delegated correctly');
+
+# change the object we are delegating too
+
my $foo = Foo->new(bar => 25);
isa_ok($foo, 'Foo');
is($bar->foo->bar, 25, '... bar->foo->bar returned the right result');
is($bar->foo_bar, 25, '... and bar->foo_bar delegated correctly again');
+# -------------------------------------------------------------------
+# ARRAY handles
+# -------------------------------------------------------------------
# we also support an array based format
-# which assumes that the name is the same
+# which assumes that the name is the same
# on either end
{
use Moose;
sub go { 'Engine::go' }
- sub stop { 'Engine::stop' }
+ sub stop { 'Engine::stop' }
package Car;
- use Moose;
-
+ use Moose;
+
has 'engine' => (
is => 'rw',
default => sub { Engine->new },
is($car->go, 'Engine::go', '... got the right value from ->go');
is($car->stop, 'Engine::stop', '... got the right value from ->stop');
+# -------------------------------------------------------------------
+# REGEXP handles
+# -------------------------------------------------------------------
# and we support regexp delegation
{
use Moose;
sub foo { 'Baz::foo' }
- sub bar { 'Baz::bar' }
- sub boo { 'Baz::boo' }
+ sub bar { 'Baz::bar' }
+ sub boo { 'Baz::boo' }
package Baz::Proxy1;
- use Moose;
-
+ use Moose;
+
has 'baz' => (
is => 'ro',
isa => 'Baz',
default => sub { Baz->new },
handles => qr/.*/
);
-
+
package Baz::Proxy2;
- use Moose;
-
+ use Moose;
+
has 'baz' => (
is => 'ro',
isa => 'Baz',
default => sub { Baz->new },
handles => qr/.oo/
- );
-
+ );
+
package Baz::Proxy3;
- use Moose;
-
+ use Moose;
+
has 'baz' => (
is => 'ro',
isa => 'Baz',
default => sub { Baz->new },
handles => qr/b.*/
- );
+ );
}
{
can_ok($baz_proxy, 'foo');
can_ok($baz_proxy, 'bar');
can_ok($baz_proxy, 'boo');
-
+
is($baz_proxy->foo, 'Baz::foo', '... got the right proxied return value');
is($baz_proxy->bar, 'Baz::bar', '... got the right proxied return value');
- is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
+ is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
}
{
my $baz_proxy = Baz::Proxy2->new;
can_ok($baz_proxy, 'foo');
can_ok($baz_proxy, 'boo');
-
+
is($baz_proxy->foo, 'Baz::foo', '... got the right proxied return value');
- is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
+ is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
}
{
my $baz_proxy = Baz::Proxy3->new;
can_ok($baz_proxy, 'bar');
can_ok($baz_proxy, 'boo');
-
+
is($baz_proxy->bar, 'Baz::bar', '... got the right proxied return value');
- is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
+ is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
}
+# -------------------------------------------------------------------
+# ROLE handles
+# -------------------------------------------------------------------
+
{
package Foo::Bar;
use Moose::Role;
-
+
requires 'foo';
requires 'bar';
-
+
package Foo::Baz;
use Moose;
-
+
sub foo { 'Foo::Baz::FOO' }
sub bar { 'Foo::Baz::BAR' }
- sub baz { 'Foo::Baz::BAZ' }
-
+ sub baz { 'Foo::Baz::BAZ' }
+
package Foo::Thing;
use Moose;
-
+
has 'thing' => (
- is => 'rw',
+ is => 'rw',
isa => 'Foo::Baz',
handles => 'Foo::Bar',
);
my $foo = Foo::Thing->new(thing => Foo::Baz->new);
isa_ok($foo, 'Foo::Thing');
isa_ok($foo->thing, 'Foo::Baz');
-
+
ok($foo->meta->has_method('foo'), '... we have the method we expect');
ok($foo->meta->has_method('bar'), '... we have the method we expect');
- ok(!$foo->meta->has_method('baz'), '... we dont have the method we expect');
-
- is($foo->foo, 'Foo::Baz::FOO', '... got the right value');
+ ok(!$foo->meta->has_method('baz'), '... we dont have the method we expect');
+
+ is($foo->foo, 'Foo::Baz::FOO', '... got the right value');
is($foo->bar, 'Foo::Baz::BAR', '... got the right value');
- is($foo->thing->baz, 'Foo::Baz::BAZ', '... got the right value');
+ is($foo->thing->baz, 'Foo::Baz::BAZ', '... got the right value');
+}
+
+# -------------------------------------------------------------------
+# AUTOLOAD & handles
+# -------------------------------------------------------------------
+
+{
+ package Foo::Autoloaded;
+ use Moose;
+
+ sub AUTOLOAD {
+ my $self = shift;
+
+ my $name = our $AUTOLOAD;
+ $name =~ s/.*://; # strip fully-qualified portion
+
+ if (@_) {
+ return $self->{$name} = shift;
+ } else {
+ return $self->{$name};
+ }
+ }
+
+ package Bar::Autoloaded;
+ use Moose;
+
+ has 'foo' => (
+ is => 'rw',
+ default => sub { Foo::Autoloaded->new },
+ handles => { 'foo_bar' => 'bar' }
+ );
+
+ package Baz::Autoloaded;
+ use Moose;
+
+ has 'foo' => (
+ is => 'rw',
+ default => sub { Foo::Autoloaded->new },
+ handles => ['bar']
+ );
+
+ package Goorch::Autoloaded;
+ use Moose;
+
+ ::dies_ok {
+ has 'foo' => (
+ is => 'rw',
+ default => sub { Foo::Autoloaded->new },
+ handles => qr/bar/
+ );
+ } '... you cannot delegate to AUTOLOADED class with regexp';
+}
+
+# check HASH based delegation w/ AUTOLOAD
+
+{
+ my $bar = Bar::Autoloaded->new;
+ isa_ok($bar, 'Bar::Autoloaded');
+
+ ok($bar->foo, '... we have something in bar->foo');
+ isa_ok($bar->foo, 'Foo::Autoloaded');
+
+ # change the value ...
+
+ $bar->foo->bar(30);
+
+ # and make sure the delegation picks it up
+
+ is($bar->foo->bar, 30, '... bar->foo->bar returned the right (changed) value');
+ is($bar->foo_bar, 30, '... bar->foo_bar delegated correctly');
+
+ # change the value through the delegation ...
+
+ $bar->foo_bar(50);
+
+ # and make sure everyone sees it
+
+ is($bar->foo->bar, 50, '... bar->foo->bar returned the right (changed) value');
+ is($bar->foo_bar, 50, '... bar->foo_bar delegated correctly');
+
+ # change the object we are delegating too
+
+ my $foo = Foo::Autoloaded->new;
+ isa_ok($foo, 'Foo::Autoloaded');
+
+ $foo->bar(25);
+
+ is($foo->bar, 25, '... got the right foo->bar');
+
+ lives_ok {
+ $bar->foo($foo);
+ } '... assigned the new Foo to Bar->foo';
+
+ is($bar->foo, $foo, '... assigned bar->foo with the new Foo');
+
+ is($bar->foo->bar, 25, '... bar->foo->bar returned the right result');
+ is($bar->foo_bar, 25, '... and bar->foo_bar delegated correctly again');
}
+# check ARRAY based delegation w/ AUTOLOAD
+
+{
+ my $baz = Baz::Autoloaded->new;
+ isa_ok($baz, 'Baz::Autoloaded');
+
+ ok($baz->foo, '... we have something in baz->foo');
+ isa_ok($baz->foo, 'Foo::Autoloaded');
+
+ # change the value ...
+
+ $baz->foo->bar(30);
+
+ # and make sure the delegation picks it up
+ is($baz->foo->bar, 30, '... baz->foo->bar returned the right (changed) value');
+ is($baz->bar, 30, '... baz->foo_bar delegated correctly');
+ # change the value through the delegation ...
+ $baz->bar(50);
+ # and make sure everyone sees it
+
+ is($baz->foo->bar, 50, '... baz->foo->bar returned the right (changed) value');
+ is($baz->bar, 50, '... baz->foo_bar delegated correctly');
+
+ # change the object we are delegating too
+
+ my $foo = Foo::Autoloaded->new;
+ isa_ok($foo, 'Foo::Autoloaded');
+
+ $foo->bar(25);
+
+ is($foo->bar, 25, '... got the right foo->bar');
+
+ lives_ok {
+ $baz->foo($foo);
+ } '... assigned the new Foo to Baz->foo';
+
+ is($baz->foo, $foo, '... assigned baz->foo with the new Foo');
+
+ is($baz->foo->bar, 25, '... baz->foo->bar returned the right result');
+ is($baz->bar, 25, '... and baz->foo_bar delegated correctly again');
+}
+
+# Check that removing attributes removes their handles methods also.
+{
+ {
+ package Quux;
+ use Moose;
+ has foo => (
+ isa => 'Foo',
+ default => sub { Foo->new },
+ handles => { 'foo_bar' => 'bar' }
+ );
+ }
+ my $i = Quux->new;
+ ok($i->meta->has_method('foo_bar'), 'handles method foo_bar is present');
+ $i->meta->remove_attribute('foo');
+ ok(!$i->meta->has_method('foo_bar'), 'handles method foo_bar is removed');
+}