redo the currying syntax to get rid of one of the arrayrefs
[gitmo/Moose.git] / t / 020_attributes / 010_attribute_delegation.t
CommitLineData
452bac1b 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6f94c802 6use Test::More tests => 92;
452bac1b 7use Test::Exception;
8
7ff56534 9
452bac1b 10
f4f3e701 11# -------------------------------------------------------------------
12# HASH handles
13# -------------------------------------------------------------------
452bac1b 14# the canonical form of of the 'handles'
d03bd989 15# option is the hash ref mapping a
452bac1b 16# method name to the delegated method name
17
18{
19 package Foo;
452bac1b 20 use Moose;
21
d03bd989 22 has 'bar' => (is => 'rw', default => 10);
452bac1b 23
227373b3 24 sub baz { 42 }
25
452bac1b 26 package Bar;
d03bd989 27 use Moose;
28
452bac1b 29 has 'foo' => (
30 is => 'rw',
31 default => sub { Foo->new },
2de18801 32 handles => {
33 'foo_bar' => 'bar',
6f94c802 34 foo_baz => 'baz',
3c573ca4 35 'foo_bar_to_20' => [ bar => 20 ],
6f94c802 36 },
452bac1b 37 );
38}
39
40my $bar = Bar->new;
41isa_ok($bar, 'Bar');
42
43ok($bar->foo, '... we have something in bar->foo');
44isa_ok($bar->foo, 'Foo');
45
01cd78f8 46my $meth = Bar->meta->get_method('foo_bar');
47isa_ok($meth, 'Moose::Meta::Method::Delegation');
48is($meth->associated_attribute->name, 'foo',
49 'associated_attribute->name for this method is foo');
a05f85c1 50
452bac1b 51is($bar->foo->bar, 10, '... bar->foo->bar returned the right default');
52
53can_ok($bar, 'foo_bar');
54is($bar->foo_bar, 10, '... bar->foo_bar delegated correctly');
55
f4f3e701 56# change the value ...
57
58$bar->foo->bar(30);
59
60# and make sure the delegation picks it up
61
62is($bar->foo->bar, 30, '... bar->foo->bar returned the right (changed) value');
63is($bar->foo_bar, 30, '... bar->foo_bar delegated correctly');
64
65# change the value through the delegation ...
66
67$bar->foo_bar(50);
68
d03bd989 69# and make sure everyone sees it
f4f3e701 70
71is($bar->foo->bar, 50, '... bar->foo->bar returned the right (changed) value');
72is($bar->foo_bar, 50, '... bar->foo_bar delegated correctly');
73
74# change the object we are delegating too
75
452bac1b 76my $foo = Foo->new(bar => 25);
77isa_ok($foo, 'Foo');
78
79is($foo->bar, 25, '... got the right foo->bar');
80
81lives_ok {
82 $bar->foo($foo);
83} '... assigned the new Foo to Bar->foo';
84
85is($bar->foo, $foo, '... assigned bar->foo with the new Foo');
86
87is($bar->foo->bar, 25, '... bar->foo->bar returned the right result');
88is($bar->foo_bar, 25, '... and bar->foo_bar delegated correctly again');
89
2de18801 90# curried handles
91$bar->foo_bar_to_20;
92is($bar->foo_bar, 20, '... correctly curried a single argument');
93
f4f3e701 94# -------------------------------------------------------------------
d03bd989 95# ARRAY handles
f4f3e701 96# -------------------------------------------------------------------
452bac1b 97# we also support an array based format
d03bd989 98# which assumes that the name is the same
452bac1b 99# on either end
100
101{
102 package Engine;
452bac1b 103 use Moose;
104
105 sub go { 'Engine::go' }
d03bd989 106 sub stop { 'Engine::stop' }
452bac1b 107
108 package Car;
d03bd989 109 use Moose;
110
452bac1b 111 has 'engine' => (
112 is => 'rw',
113 default => sub { Engine->new },
114 handles => [ 'go', 'stop' ]
115 );
116}
117
118my $car = Car->new;
119isa_ok($car, 'Car');
120
121isa_ok($car->engine, 'Engine');
122can_ok($car->engine, 'go');
123can_ok($car->engine, 'stop');
124
125is($car->engine->go, 'Engine::go', '... got the right value from ->engine->go');
126is($car->engine->stop, 'Engine::stop', '... got the right value from ->engine->stop');
127
128can_ok($car, 'go');
129can_ok($car, 'stop');
130
131is($car->go, 'Engine::go', '... got the right value from ->go');
132is($car->stop, 'Engine::stop', '... got the right value from ->stop');
133
f4f3e701 134# -------------------------------------------------------------------
d03bd989 135# REGEXP handles
f4f3e701 136# -------------------------------------------------------------------
452bac1b 137# and we support regexp delegation
138
139{
140 package Baz;
452bac1b 141 use Moose;
142
143 sub foo { 'Baz::foo' }
d03bd989 144 sub bar { 'Baz::bar' }
145 sub boo { 'Baz::boo' }
452bac1b 146
147 package Baz::Proxy1;
d03bd989 148 use Moose;
149
452bac1b 150 has 'baz' => (
151 is => 'ro',
152 isa => 'Baz',
153 default => sub { Baz->new },
154 handles => qr/.*/
155 );
d03bd989 156
452bac1b 157 package Baz::Proxy2;
d03bd989 158 use Moose;
159
452bac1b 160 has 'baz' => (
161 is => 'ro',
162 isa => 'Baz',
163 default => sub { Baz->new },
164 handles => qr/.oo/
d03bd989 165 );
166
452bac1b 167 package Baz::Proxy3;
d03bd989 168 use Moose;
169
452bac1b 170 has 'baz' => (
171 is => 'ro',
172 isa => 'Baz',
173 default => sub { Baz->new },
174 handles => qr/b.*/
d03bd989 175 );
452bac1b 176}
177
178{
179 my $baz_proxy = Baz::Proxy1->new;
180 isa_ok($baz_proxy, 'Baz::Proxy1');
181
182 can_ok($baz_proxy, 'baz');
183 isa_ok($baz_proxy->baz, 'Baz');
184
185 can_ok($baz_proxy, 'foo');
186 can_ok($baz_proxy, 'bar');
187 can_ok($baz_proxy, 'boo');
d03bd989 188
452bac1b 189 is($baz_proxy->foo, 'Baz::foo', '... got the right proxied return value');
190 is($baz_proxy->bar, 'Baz::bar', '... got the right proxied return value');
d03bd989 191 is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
452bac1b 192}
193{
194 my $baz_proxy = Baz::Proxy2->new;
195 isa_ok($baz_proxy, 'Baz::Proxy2');
196
197 can_ok($baz_proxy, 'baz');
198 isa_ok($baz_proxy->baz, 'Baz');
199
200 can_ok($baz_proxy, 'foo');
201 can_ok($baz_proxy, 'boo');
d03bd989 202
452bac1b 203 is($baz_proxy->foo, 'Baz::foo', '... got the right proxied return value');
d03bd989 204 is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
452bac1b 205}
206{
207 my $baz_proxy = Baz::Proxy3->new;
208 isa_ok($baz_proxy, 'Baz::Proxy3');
209
210 can_ok($baz_proxy, 'baz');
211 isa_ok($baz_proxy->baz, 'Baz');
212
213 can_ok($baz_proxy, 'bar');
214 can_ok($baz_proxy, 'boo');
d03bd989 215
452bac1b 216 is($baz_proxy->bar, 'Baz::bar', '... got the right proxied return value');
d03bd989 217 is($baz_proxy->boo, 'Baz::boo', '... got the right proxied return value');
452bac1b 218}
219
f4f3e701 220# -------------------------------------------------------------------
221# ROLE handles
222# -------------------------------------------------------------------
223
c84f324f 224{
225 package Foo::Bar;
226 use Moose::Role;
d03bd989 227
c84f324f 228 requires 'foo';
229 requires 'bar';
d03bd989 230
c84f324f 231 package Foo::Baz;
232 use Moose;
d03bd989 233
c84f324f 234 sub foo { 'Foo::Baz::FOO' }
235 sub bar { 'Foo::Baz::BAR' }
d03bd989 236 sub baz { 'Foo::Baz::BAZ' }
237
c84f324f 238 package Foo::Thing;
239 use Moose;
d03bd989 240
c84f324f 241 has 'thing' => (
d03bd989 242 is => 'rw',
c84f324f 243 isa => 'Foo::Baz',
244 handles => 'Foo::Bar',
245 );
246
247}
248
249{
250 my $foo = Foo::Thing->new(thing => Foo::Baz->new);
251 isa_ok($foo, 'Foo::Thing');
252 isa_ok($foo->thing, 'Foo::Baz');
d03bd989 253
c84f324f 254 ok($foo->meta->has_method('foo'), '... we have the method we expect');
255 ok($foo->meta->has_method('bar'), '... we have the method we expect');
d03bd989 256 ok(!$foo->meta->has_method('baz'), '... we dont have the method we expect');
257
258 is($foo->foo, 'Foo::Baz::FOO', '... got the right value');
c84f324f 259 is($foo->bar, 'Foo::Baz::BAR', '... got the right value');
d03bd989 260 is($foo->thing->baz, 'Foo::Baz::BAZ', '... got the right value');
c84f324f 261}
262
e902b1a5 263# -------------------------------------------------------------------
264# AUTOLOAD & handles
265# -------------------------------------------------------------------
266
267{
268 package Foo::Autoloaded;
269 use Moose;
270
271 sub AUTOLOAD {
272 my $self = shift;
273
274 my $name = our $AUTOLOAD;
f4fce6c8 275 $name =~ s/.*://; # strip fully-qualified portion
e902b1a5 276
277 if (@_) {
278 return $self->{$name} = shift;
279 } else {
280 return $self->{$name};
281 }
282 }
283
284 package Bar::Autoloaded;
d03bd989 285 use Moose;
286
e902b1a5 287 has 'foo' => (
288 is => 'rw',
289 default => sub { Foo::Autoloaded->new },
290 handles => { 'foo_bar' => 'bar' }
291 );
d03bd989 292
e902b1a5 293 package Baz::Autoloaded;
d03bd989 294 use Moose;
295
e902b1a5 296 has 'foo' => (
297 is => 'rw',
298 default => sub { Foo::Autoloaded->new },
299 handles => ['bar']
d03bd989 300 );
301
e902b1a5 302 package Goorch::Autoloaded;
d03bd989 303 use Moose;
304
e902b1a5 305 ::dies_ok {
306 has 'foo' => (
307 is => 'rw',
308 default => sub { Foo::Autoloaded->new },
309 handles => qr/bar/
d03bd989 310 );
e902b1a5 311 } '... you cannot delegate to AUTOLOADED class with regexp';
312}
313
314# check HASH based delegation w/ AUTOLOAD
315
316{
317 my $bar = Bar::Autoloaded->new;
318 isa_ok($bar, 'Bar::Autoloaded');
319
320 ok($bar->foo, '... we have something in bar->foo');
321 isa_ok($bar->foo, 'Foo::Autoloaded');
322
323 # change the value ...
324
325 $bar->foo->bar(30);
326
327 # and make sure the delegation picks it up
328
329 is($bar->foo->bar, 30, '... bar->foo->bar returned the right (changed) value');
330 is($bar->foo_bar, 30, '... bar->foo_bar delegated correctly');
331
332 # change the value through the delegation ...
333
334 $bar->foo_bar(50);
335
d03bd989 336 # and make sure everyone sees it
e902b1a5 337
338 is($bar->foo->bar, 50, '... bar->foo->bar returned the right (changed) value');
339 is($bar->foo_bar, 50, '... bar->foo_bar delegated correctly');
340
341 # change the object we are delegating too
342
343 my $foo = Foo::Autoloaded->new;
344 isa_ok($foo, 'Foo::Autoloaded');
345
346 $foo->bar(25);
d03bd989 347
e902b1a5 348 is($foo->bar, 25, '... got the right foo->bar');
349
350 lives_ok {
351 $bar->foo($foo);
352 } '... assigned the new Foo to Bar->foo';
353
354 is($bar->foo, $foo, '... assigned bar->foo with the new Foo');
355
356 is($bar->foo->bar, 25, '... bar->foo->bar returned the right result');
357 is($bar->foo_bar, 25, '... and bar->foo_bar delegated correctly again');
358}
359
360# check ARRAY based delegation w/ AUTOLOAD
361
362{
363 my $baz = Baz::Autoloaded->new;
364 isa_ok($baz, 'Baz::Autoloaded');
365
366 ok($baz->foo, '... we have something in baz->foo');
367 isa_ok($baz->foo, 'Foo::Autoloaded');
368
369 # change the value ...
370
371 $baz->foo->bar(30);
372
373 # and make sure the delegation picks it up
374
375 is($baz->foo->bar, 30, '... baz->foo->bar returned the right (changed) value');
376 is($baz->bar, 30, '... baz->foo_bar delegated correctly');
377
378 # change the value through the delegation ...
379
380 $baz->bar(50);
381
d03bd989 382 # and make sure everyone sees it
e902b1a5 383
384 is($baz->foo->bar, 50, '... baz->foo->bar returned the right (changed) value');
385 is($baz->bar, 50, '... baz->foo_bar delegated correctly');
386
387 # change the object we are delegating too
388
389 my $foo = Foo::Autoloaded->new;
390 isa_ok($foo, 'Foo::Autoloaded');
391
392 $foo->bar(25);
d03bd989 393
e902b1a5 394 is($foo->bar, 25, '... got the right foo->bar');
395
396 lives_ok {
397 $baz->foo($foo);
398 } '... assigned the new Foo to Baz->foo';
399
400 is($baz->foo, $foo, '... assigned baz->foo with the new Foo');
401
402 is($baz->foo->bar, 25, '... baz->foo->bar returned the right result');
403 is($baz->bar, 25, '... and baz->foo_bar delegated correctly again');
404}
e1d6f0a3 405
406# Check that removing attributes removes their handles methods also.
407{
408 {
409 package Quux;
410 use Moose;
d03bd989 411 has foo => (
412 isa => 'Foo',
e1d6f0a3 413 default => sub { Foo->new },
414 handles => { 'foo_bar' => 'bar' }
415 );
416 }
417 my $i = Quux->new;
418 ok($i->meta->has_method('foo_bar'), 'handles method foo_bar is present');
419 $i->meta->remove_attribute('foo');
420 ok(!$i->meta->has_method('foo_bar'), 'handles method foo_bar is removed');
421}
422
ad5e9d0d 423# Make sure that a useful error message is thrown when the delegation target is
424# not an object
425{
6148c167 426 my $i = Bar->new(foo => undef);
427 throws_ok { $i->foo_bar } qr/is not defined/,
428 'useful error from unblessed reference';
429
430 my $j = Bar->new(foo => []);
431 throws_ok { $j->foo_bar } qr/is not an object \(got 'ARRAY/,
ad5e9d0d 432 'useful error from unblessed reference';
227373b3 433
434 my $k = Bar->new(foo => "Foo");
435 lives_ok { $k->foo_baz } "but not for class name";
ad5e9d0d 436}