Commit | Line | Data |
0558683c |
1 | #!/usr/bin/perl |
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
e7f8d0c2 |
6 | use Test::More tests => 17; |
0558683c |
7 | use Test::Exception; |
8 | |
1db8ecc7 |
9 | =pod |
10 | |
11 | NOTE: |
12 | A fair amount of these tests will likely be irrelevant |
13 | once we have more fine grained control over the class |
14 | building process. A lot of the edge cases tested here |
15 | are actually related to class construction order and |
16 | not any real functionality. |
17 | - SL |
18 | |
19 | =cut |
20 | |
0558683c |
21 | BEGIN { |
22 | use_ok('Moose'); |
23 | use_ok('Moose::Role'); |
24 | } |
25 | |
26 | =pod |
27 | |
28 | Role which requires a method implemented |
29 | in another role as an override (it does |
30 | not remove the requirement) |
31 | |
32 | =cut |
33 | |
34 | { |
35 | package Role::RequireFoo; |
36 | use strict; |
37 | use warnings; |
38 | use Moose::Role; |
39 | |
40 | requires 'foo'; |
41 | |
42 | package Role::ProvideFoo; |
43 | use strict; |
44 | use warnings; |
45 | use Moose::Role; |
46 | |
47 | ::lives_ok { |
48 | with 'Role::RequireFoo'; |
49 | } '... the required "foo" method will not exist yet (but we will live)'; |
50 | |
51 | override 'foo' => sub { 'Role::ProvideFoo::foo' }; |
52 | } |
53 | |
54 | is_deeply( |
55 | [ Role::ProvideFoo->meta->get_required_method_list ], |
56 | [ 'foo' ], |
57 | '... foo method is still required for Role::ProvideFoo'); |
58 | |
59 | =pod |
60 | |
61 | Role which requires a method implemented |
62 | in the consuming class as an override. |
63 | It will fail since method modifiers are |
64 | second class citizens. |
65 | |
66 | =cut |
67 | |
68 | { |
69 | package Class::ProvideFoo::Base; |
70 | use Moose; |
71 | |
72 | sub foo { 'Class::ProvideFoo::Base::foo' } |
73 | |
74 | package Class::ProvideFoo::Override1; |
75 | use Moose; |
76 | |
77 | extends 'Class::ProvideFoo::Base'; |
78 | |
1db8ecc7 |
79 | ::lives_ok { |
0558683c |
80 | with 'Role::RequireFoo'; |
1db8ecc7 |
81 | } '... the required "foo" method will be found in the superclass'; |
0558683c |
82 | |
83 | override 'foo' => sub { 'Class::ProvideFoo::foo' }; |
84 | |
85 | package Class::ProvideFoo::Override2; |
86 | use Moose; |
87 | |
88 | extends 'Class::ProvideFoo::Base'; |
89 | |
90 | override 'foo' => sub { 'Class::ProvideFoo::foo' }; |
91 | |
e7f8d0c2 |
92 | ::lives_ok { |
0558683c |
93 | with 'Role::RequireFoo'; |
e7f8d0c2 |
94 | } '... the required "foo" method exists, although it is overriden locally'; |
0558683c |
95 | |
96 | } |
97 | |
98 | =pod |
99 | |
100 | Now same thing, but with a before |
101 | method modifier. |
102 | |
103 | =cut |
104 | |
105 | { |
106 | package Class::ProvideFoo::Before1; |
107 | use Moose; |
108 | |
109 | extends 'Class::ProvideFoo::Base'; |
110 | |
1db8ecc7 |
111 | ::lives_ok { |
0558683c |
112 | with 'Role::RequireFoo'; |
1db8ecc7 |
113 | } '... the required "foo" method will be found in the superclass'; |
0558683c |
114 | |
115 | before 'foo' => sub { 'Class::ProvideFoo::foo:before' }; |
116 | |
117 | package Class::ProvideFoo::Before2; |
118 | use Moose; |
119 | |
120 | extends 'Class::ProvideFoo::Base'; |
121 | |
122 | before 'foo' => sub { 'Class::ProvideFoo::foo:before' }; |
123 | |
e7f8d0c2 |
124 | ::lives_ok { |
0558683c |
125 | with 'Role::RequireFoo'; |
e7f8d0c2 |
126 | } '... the required "foo" method exists, although it is a before modifier locally'; |
0558683c |
127 | |
128 | package Class::ProvideFoo::Before3; |
129 | use Moose; |
130 | |
131 | extends 'Class::ProvideFoo::Base'; |
132 | |
0558683c |
133 | sub foo { 'Class::ProvideFoo::foo' } |
134 | before 'foo' => sub { 'Class::ProvideFoo::foo:before' }; |
135 | |
e7f8d0c2 |
136 | ::lives_ok { |
137 | with 'Role::RequireFoo'; |
138 | } '... the required "foo" method exists locally, and it is modified locally'; |
139 | |
0558683c |
140 | package Class::ProvideFoo::Before4; |
141 | use Moose; |
142 | |
143 | extends 'Class::ProvideFoo::Base'; |
144 | |
145 | sub foo { 'Class::ProvideFoo::foo' } |
146 | before 'foo' => sub { 'Class::ProvideFoo::foo:before' }; |
147 | |
148 | ::isa_ok(__PACKAGE__->meta->get_method('foo'), 'Class::MOP::Method::Wrapped'); |
149 | ::is(__PACKAGE__->meta->get_method('foo')->get_original_method->package_name, __PACKAGE__, |
150 | '... but the original method is from our package'); |
151 | |
152 | ::lives_ok { |
153 | with 'Role::RequireFoo'; |
154 | } '... the required "foo" method exists in the symbol table (and we will live)'; |
e7f8d0c2 |
155 | |
0558683c |
156 | } |
157 | |
158 | =pod |
159 | |
160 | Now same thing, but with a method from an attribute |
161 | method modifier. |
162 | |
163 | =cut |
164 | |
165 | { |
166 | |
167 | package Class::ProvideFoo::Attr1; |
168 | use Moose; |
169 | |
170 | extends 'Class::ProvideFoo::Base'; |
171 | |
1db8ecc7 |
172 | ::lives_ok { |
0558683c |
173 | with 'Role::RequireFoo'; |
1db8ecc7 |
174 | } '... the required "foo" method will be found in the superclass (but then overriden)'; |
0558683c |
175 | |
176 | has 'foo' => (is => 'ro'); |
177 | |
178 | package Class::ProvideFoo::Attr2; |
179 | use Moose; |
180 | |
181 | extends 'Class::ProvideFoo::Base'; |
182 | |
183 | has 'foo' => (is => 'ro'); |
184 | |
185 | ::dies_ok { |
186 | with 'Role::RequireFoo'; |
187 | } '... the required "foo" method exists, but it is a before (and we will die)'; |
188 | } |
825a80de |
189 | |
190 | # ... |
191 | # a method required in a role, but then |
192 | # implemented in the superclass (as an |
193 | # attribute accessor too) |
194 | |
195 | { |
196 | package Foo::Class::Base; |
197 | use Moose; |
198 | |
199 | has 'bar' => ( |
200 | isa => 'Int', |
201 | is => 'rw', |
202 | default => sub { 1 } |
203 | ); |
204 | } |
205 | { |
206 | package Foo::Role; |
207 | use Moose::Role; |
208 | |
209 | requires 'bar'; |
0558683c |
210 | |
825a80de |
211 | has 'foo' => ( |
212 | isa => 'Int', |
213 | is => 'rw', |
214 | lazy => 1, |
215 | default => sub { (shift)->bar + 1 } |
216 | ); |
217 | } |
218 | { |
219 | package Foo::Class::Child; |
220 | use Moose; |
221 | extends 'Foo::Class::Base'; |
222 | |
223 | ::dies_ok { |
224 | with 'Foo::Role'; |
225 | } '... our role combined successfully'; |
226 | } |
227 | |
3dd18b73 |
228 | # a method required in a role and implemented in a superclass, with a method |
229 | # modifier in the subclass. this should live, but dies in 0.26 -- hdp, |
230 | # 2007-10-11 |
825a80de |
231 | |
3dd18b73 |
232 | { |
233 | package Bar::Class::Base; |
234 | use Moose; |
825a80de |
235 | |
3dd18b73 |
236 | sub bar { "hello!" } |
237 | } |
238 | { |
239 | package Bar::Role; |
240 | use Moose::Role; |
241 | requires 'bar'; |
242 | } |
243 | { |
244 | package Bar::Class::Child; |
245 | use Moose; |
246 | extends 'Bar::Class::Base'; |
247 | after bar => sub { "o noes" }; |
4ec69f21 |
248 | # technically we could run lives_ok here, too, but putting it into a |
249 | # grandchild class makes it more obvious why this matters. |
250 | } |
251 | { |
252 | package Bar::Class::Grandchild; |
253 | use Moose; |
254 | extends 'Bar::Class::Child'; |
3dd18b73 |
255 | ::lives_ok { |
256 | with 'Bar::Role'; |
257 | } 'required method exists in superclass as non-modifier, so we live'; |
258 | } |
e7f8d0c2 |
259 | |
260 | { |
261 | package Bar2::Class::Base; |
262 | use Moose; |
263 | |
264 | sub bar { "hello!" } |
265 | } |
266 | { |
267 | package Bar2::Role; |
268 | use Moose::Role; |
269 | requires 'bar'; |
270 | } |
271 | { |
272 | package Bar2::Class::Child; |
273 | use Moose; |
274 | extends 'Bar2::Class::Base'; |
275 | override bar => sub { "o noes" }; |
276 | # technically we could run lives_ok here, too, but putting it into a |
277 | # grandchild class makes it more obvious why this matters. |
278 | } |
279 | { |
280 | package Bar2::Class::Grandchild; |
281 | use Moose; |
282 | extends 'Bar2::Class::Child'; |
283 | ::lives_ok { |
284 | with 'Bar2::Role'; |
285 | } 'required method exists in superclass as non-modifier, so we live'; |
286 | } |