Reorder changes to put most interesting ones first
[gitmo/Moose.git] / t / 600_todo_tests / 002_various_role_features.t
CommitLineData
bbc9f1c6 1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
a28e50e4 6use Test::More;
bbc9f1c6 7use Test::Exception;
8
9sub req_or_has ($$) {
10 my ( $role, $method ) = @_;
11 local $Test::Builder::Level = $Test::Builder::Level + 1;
12 if ( $role ) {
d03bd989 13 ok(
14 $role->has_method($method) || $role->requires_method($method),
15 $role->name . " has or requires method $method"
68b6146c 16 );
bbc9f1c6 17 } else {
18 fail("role has or requires method $method");
19 }
20}
21
1344fd47 22{
23 package Bar;
24 use Moose::Role;
bbc9f1c6 25
26 # this role eventually adds three methods, qw(foo bar xxy), but only one is
27 # known when it's still a role
28
1344fd47 29 has foo => ( is => "rw" );
bbc9f1c6 30
31 has gorch => ( reader => "bar" );
32
33 sub xxy { "BAAAD" }
34
35 package Gorch;
36 use Moose::Role;
37
38 # similarly this role gives attr and gorch_method
39
40 has attr => ( is => "rw" );
41
42 sub gorch_method { "gorch method" }
43
44 around dandy => sub { shift->(@_) . "bar" };
45
46 package Quxx;
47 use Moose;
48
49 sub dandy { "foo" }
50
51 # this object will be used in an attr of Foo to test that Foo can do the
52 # Gorch interface
53
54 with qw(Gorch);
55
56 package Dancer;
57 use Moose::Role;
58
59 requires "twist";
60
61 package Dancer::Ballerina;
62 use Moose;
63
64 with qw(Dancer);
65
66 sub twist { }
67
68 sub pirouette { }
69
70 package Dancer::Robot;
71 use Moose::Role;
72
73 # this doesn't fail but it produces a requires in the role
74 # the order doesn't matter
75 has twist => ( is => "rw" );
76 ::lives_ok { with qw(Dancer) };
77
78 package Dancer::Something;
79 use Moose;
80
81 # this fail even though the method already exists
82
83 has twist => ( is => "rw" );
84
85 {
bbc9f1c6 86 ::lives_ok { with qw(Dancer) };
87 }
88
89 package Dancer::80s;
90 use Moose;
91
92 # this should pass because ::Robot has the attribute to fill in the requires
93 # but due to the deferrence logic that doesn't actually work
94 {
95 local our $TODO = "attribute accessor in role doesn't satisfy role requires";
96 ::lives_ok { with qw(Dancer::Robot) };
97 }
98
1344fd47 99 package Foo;
100 use Moose;
bbc9f1c6 101
f6bee6fe 102 with qw(Bar);
bbc9f1c6 103
104 has oink => (
105 is => "rw",
106 handles => "Gorch", # should handles take the same arguments as 'with'? Meta::Role::Application::Delegation?
107 default => sub { Quxx->new },
108 );
109
110 has dancer => (
111 is => "rw",
112 does => "Dancer",
113 handles => "Dancer",
114 default => sub { Dancer::Ballerina->new },
115 );
116
1344fd47 117 sub foo { 42 }
bbc9f1c6 118
119 sub bar { 33 }
120
121 sub xxy { 7 }
e953aaf5 122
123 package Tree;
124 use Moose::Role;
d03bd989 125
e953aaf5 126 has bark => ( is => "rw" );
127
128 package Dog;
129 use Moose::Role;
d03bd989 130
e953aaf5 131 sub bark { warn "woof!" };
132
133 package EntPuppy;
134 use Moose;
135
136 {
137 local our $TODO = "attrs and methods from a role should clash";
138 ::dies_ok { with qw(Tree Dog) }
139 }
bbc9f1c6 140}
141
142# these fail because of the deferral logic winning over actual methods
143# this might be tricky to fix due to the 'sub foo {}; has foo => ( )' hack
144# we've been doing for a long while, though I doubt people relied on it for
145# anything other than fulfilling 'requires'
146{
147 local $TODO = "attributes from role overwrite class methods";
148 is( Foo->new->foo, 42, "attr did not zap overriding method" );
149 is( Foo->new->bar, 33, "attr did not zap overriding method" );
150}
151is( Foo->new->xxy, 7, "method did not zap overriding method" ); # duh
152
153# these pass, simple delegate
154# mostly they are here to contrast the next blck
155can_ok( Foo->new->oink, "dandy" );
156can_ok( Foo->new->oink, "attr" );
157can_ok( Foo->new->oink, "gorch_method" );
158
159ok( Foo->new->oink->does("Gorch"), "Quxx does Gorch" );
160
161
162# these are broken because 'attr' is not technically part of the interface
163can_ok( Foo->new, "gorch_method" );
164{
165 local $TODO = "accessor methods from a role are omitted in handles role";
166 can_ok( Foo->new, "attr" );
167}
168
169{
170 local $TODO = "handles role doesn't add the role to the ->does of the delegate's parent class";
171 ok( Foo->new->does("Gorch"), "Foo does Gorch" );
172}
173
174
175# these work
176can_ok( Foo->new->dancer, "pirouette" );
177can_ok( Foo->new->dancer, "twist" );
178
179can_ok( Foo->new, "twist" );
180ok( !Foo->new->can("pirouette"), "can't pirouette, not part of the iface" );
181
182{
183 local $TODO = "handles role doesn't add the role to the ->does of the delegate's parent class";
184 ok( Foo->new->does("Dancer") );
185}
186
187
188
189
190my $gorch = Gorch->meta;
191
192isa_ok( $gorch, "Moose::Meta::Role" );
193
194ok( $gorch->has_attribute("attr"), "has attribute 'attr'" );
195
196{
197 local $TODO = "role attribute isn't a meta attribute yet";
198 isa_ok( $gorch->get_attribute("attr"), "Moose::Meta::Attribute" );
199}
200
201req_or_has($gorch, "gorch_method");
202ok( $gorch->has_method("gorch_method"), "has_method gorch_method" );
203ok( !$gorch->requires_method("gorch_method"), "requires gorch method" );
9cde8a2f 204isa_ok( $gorch->get_method("gorch_method"), "Moose::Meta::Method" );
bbc9f1c6 205
206{
207 local $TODO = "method modifier doesn't yet create a method requirement or meta object";
208 req_or_has($gorch, "dandy" );
209
210 # this specific test is maybe not backwards compat, but in theory it *does*
211 # require that method to exist
212 ok( $gorch->requires_method("dandy"), "requires the dandy method for the modifier" );
213}
214
215{
216 local $TODO = "attribute related methods are not yet known by the role";
217 # we want this to be a part of the interface, somehow
218 req_or_has($gorch, "attr");
219 ok( $gorch->has_method("attr"), "has_method attr" );
220 isa_ok( $gorch->get_method("attr"), "Moose::Meta::Method" );
221 isa_ok( $gorch->get_method("attr"), "Moose::Meta::Method::Accessor" );
222}
223
224my $robot = Dancer::Robot->meta;
225
226isa_ok( $robot, "Moose::Meta::Role" );
227
228ok( $robot->has_attribute("twist"), "has attr 'twist'" );
229
230{
231 local $TODO = "role attribute isn't a meta attribute yet";
232 isa_ok( $robot->get_attribute("twist"), "Moose::Meta::Attribute" );
233}
234
235{
bbc9f1c6 236 req_or_has($robot, "twist");
a632beb5 237
238 local $TODO = "attribute related methods are not yet known by the role";
bbc9f1c6 239 ok( $robot->has_method("twist"), "has twist method" );
240 isa_ok( $robot->get_method("twist"), "Moose::Meta::Method" );
241 isa_ok( $robot->get_method("twist"), "Moose::Meta::Method::Accessor" );
242}
243
a28e50e4 244done_testing;
245
bbc9f1c6 246__END__
247
248I think Attribute needs to be refactored in some way to better support roles.
249
250There are several possible ways to do this, all of them seem plausible to me.
251
252The first approach would be to change the attribute class to allow it to be
253queried about the methods it would install.
254
255Then we instantiate the attribute in the role, and instead of deferring the
256arguments, we just make an C<unpack>ish method.
257
258Then we can interrogate the attr when adding it to the role, and generate stub
259methods for all the methods it would produce.
260
261A second approach is kinda like the Immutable hack: wrap the attr in an
262anonmyous class that disables part of its interface.
263
264A third method would be to create an Attribute::Partial object that would
265provide a more role-ish behavior, and to do this independently of the actual
266Attribute class.
267
268Something similar can be done for method modifiers, but I think that's even simpler.
269
270
271
272The benefits of doing this are:
273
274* Much better introspection of roles
275
276* More correctness in many cases (in my opinion anyway)
277
278* More roles are more usable as interface declarations, without having to split
279 them into two pieces (one for the interface with a bunch of requires(), and
280 another for the actual impl with the problematic attrs (and stub methods to
281 fix the accessors) and method modifiers (dunno if this can even work at all)
282
283