Codebase list libmoose-perl / 9dbc5b3
[svn-upgrade] Integrating new upstream version, libmoose-perl (0.80) Salvatore Bonaccorso 14 years ago
66 changed file(s) with 880 addition(s) and 420 deletion(s). Raw diff Collapse all Expand all
00 Also see Moose::Manual::Delta for more details of, and workarounds
11 for, noteworthy changes.
2
3 0.80 Sat, Jun 6, 2009
4 * Moose::Manual::FAQ
5 - Add FAQ about the coercion change from 0.76 because it came up
6 three times today (perigrin)
7 - Win doy $10 dollars because Sartak didn't think anybody
8 would document this fast enough (perigrin)
9
10 * Moose::Meta::Method::Destructor
11 - Inline a DESTROY method even if there are no DEMOLISH methods
12 to prevent unnecessary introspection in
13 Moose::Object::DEMOLISHALL
14
15 * Moose::*
16 - A role's required methods are now represented by
17 Moose::Meta::Role::Method::Required objects. Conflicts are now
18 represented by Moose::Meta::Role::Method::Conflicting
19 objects. The benefit for end-users in that unresolved
20 conflicts generate different, more instructive, errors,
21 resolving Ovid's #44895. (Sartak)
22
23 * Moose::Role
24 - Improve the error message of "extends" as suggested by Adam
25 Kennedy and confound (Sartak)
26 - Link to Moose::Manual::Roles from Moose::Role as we now have
27 excellent documentation (Adam Kennedy)
28
29 * Tests
30 - Update test suite for subname change in Class::MOP
31 (nothingmuch)
32 - Add TODO test for infinite recursion in Moose::Meta::Class
33 (groditi)
234
335 0.79 Wed, May 13, 2009
436 * Tests
941 during global destruction. This method has been made more
1042 resilient in the face of global destruction's random garbage
1143 collection order.
44
45 * Moose::Exporter
46 - If you "also" a module that isn't loaded, the error message
47 now acknowledges that (Sartak)
48
49 * Moose
50 - When your ->meta method does not return a Moose::Meta::Class,
51 the error message gave the wrong output (Sartak)
1252
1353 0.78 Tue, May 12, 2009
1454 * Moose::Cookbook::FAQ and Moose::Cookbook::WTF
7979 lib/Moose/Meta/Role/Application/ToRole.pm
8080 lib/Moose/Meta/Role/Composite.pm
8181 lib/Moose/Meta/Role/Method.pm
82 lib/Moose/Meta/Role/Method/Conflicting.pm
8283 lib/Moose/Meta/Role/Method/Required.pm
8384 lib/Moose/Meta/TypeCoercion.pm
8485 lib/Moose/Meta/TypeCoercion/Union.pm
280281 t/100_bugs/021_DEMOLISHALL_shortcutted.t
281282 t/100_bugs/022_role_caller.t
282283 t/100_bugs/023_DEMOLISH_fails_without_metaclass.t
284 t/100_bugs/024_anon_method_metaclass.t
285 t/100_bugs/025_universal_methods_wrappable.t
286 t/100_bugs/026_create_anon_recursion.t
283287 t/200_examples/001_example.t
284288 t/200_examples/002_example_Moose_POOP.t
285289 t/200_examples/003_example.t
300304 t/300_immutable/011_constructor_is_wrapped.t
301305 t/300_immutable/012_default_values.t
302306 t/300_immutable/013_immutable_roundtrip.t
307 t/300_immutable/014_immutable_metaclass_with_traits.t
303308 t/400_moose_util/001_moose_util.t
304309 t/400_moose_util/002_moose_util_does_role.t
305310 t/400_moose_util/003_moose_util_search_class_by_role.t
310315 t/500_test_moose/003_test_moose_has_attribute_ok.t
311316 t/500_test_moose/004_test_moose_meta_ok.t
312317 t/600_todo_tests/001_exception_reflects_failed_constraint.t
313 t/600_todo_tests/002_various_role_shit.t
318 t/600_todo_tests/002_various_role_features.t
314319 t/600_todo_tests/003_immutable_n_around.t
315320 t/600_todo_tests/005_moose_and_threads.t
316321 t/600_todo_tests/006_moose_nonmoose_metatrait_init_order.t
3131 perl: 5.8.1
3232 resources:
3333 license: http://dev.perl.org/licenses/
34 version: 0.79
34 version: 0.80
0 Moose version 0.79
0 Moose version 0.80
11 ===========================
22
33 See the individual module documentation for more information
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
7575 sub _follow_also_real {
7676 my $exporting_package = shift;
7777
78 die "Package in also ($exporting_package) does not seem to use Moose::Exporter"
79 unless exists $EXPORT_SPEC{$exporting_package};
78 if (!exists $EXPORT_SPEC{$exporting_package}) {
79 my $loaded = Class::MOP::is_class_loaded($exporting_package);
80
81 die "Package in also ($exporting_package) does not seem to "
82 . "use Moose::Exporter"
83 . ($loaded ? "" : " (is it loaded?)");
84 }
8085
8186 my $also = $EXPORT_SPEC{$exporting_package}{also};
8287
181186 return sub {
182187 my $caller = $CALLER;
183188
184 my $wrapper = $self->_make_wrapper($caller, $sub, $fq_name);
189 my $wrapper = $self->_curry_wrapper($sub, $fq_name, $caller);
185190
186191 my $sub = subname($fq_name => $wrapper);
187192
191196 };
192197 }
193198
194 sub _make_wrapper {
199 sub _curry_wrapper {
195200 my $class = shift;
196 my $caller = shift;
197201 my $sub = shift;
198202 my $fq_name = shift;
199
200 my $wrapper = sub { $sub->($caller, @_) };
203 my @extra = @_;
204
205 my $wrapper = sub { $sub->(@extra, @_) };
201206 if (my $proto = prototype $sub) {
202207 # XXX - Perl's prototype sucks. Use & to make set_prototype
203 # ignore the fact that we're passing a "provate variable"
208 # ignore the fact that we're passing "private variables"
204209 &Scalar::Util::set_prototype($wrapper, $proto);
205210 }
206211 return $wrapper;
413418
414419 sub has_rw {
415420 my ($caller, $name, %options) = @_;
416 Class::MOP::Class->initialize($caller)->add_attribute($name,
421 Class::MOP::class_of($caller)->add_attribute($name,
417422 is => 'rw',
418423 %options,
419424 );
159159 There are a couple caveats worth mentioning in regards to what
160160 "required" actually means.
161161
162 Basically, all it says is that this attribute (C<name>) must be provided
163 to the constructor. It does not say anything about its value, so it
164 could be C<undef>.
162 Basically, all it says is that this attribute (C<name>) must be provided to
163 the constructor, or be lazy with either a default or a builder. It does not
164 say anything about its value, so it could be C<undef>.
165165
166166 If you define a clearer method on a required attribute, the clearer
167167 I<will> work, so even a required attribute can be unset after object
184184 C<< "replace_constructor => 1 >> to C<make_immutable>.
185185
186186 If you want to get rid of the warning, pass C<< inline_constructor =>
187 1 >>.
187 0 >>.
188188
189189 =head1 Version 0.62
190190
279279 =head3 Can I turn off type constraint checking?
280280
281281 Not yet. This option may come in a future release.
282
283 =head3 My coercions stopped working with recent Moose, why did you break it?
284
285 Moose 0.76 fixed a case where Coercions were being applied even if the original constraint passed. This has caused some edge cases to fail where people were doing something like
286
287 subtype Address => as 'Str';
288 coerce Address => from Str => via { get_address($_) };
289
290 Which is not what they intended. The Type Constraint C<Address> is too loose in this case, it is saying that all Strings are Addresses, which is obviously not the case. The solution is to provide a where clause that properly restricts the Type Constraint.
291
292 subtype Address => as Str => where { looks_like_address($_) };
293
294 This will allow the coercion to apply only to strings that fail to look like an Address.
282295
283296 =head2 Roles
284297
66 use Scalar::Util 'blessed', 'weaken';
77 use overload ();
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
1212 use Moose::Meta::Method::Accessor;
347347 $class->throw_error("You can not use lazy_build and default for the same attribute ($name)", data => $options)
348348 if exists $options->{default};
349349 $options->{lazy} = 1;
350 $options->{required} = 1;
351350 $options->{builder} ||= "_build_${name}";
352351 if ($name =~ /^_/) {
353352 $options->{clearer} ||= "_clear${name}";
627626
628627 return map { $_ => $_ } (
629628 $role_meta->get_method_list,
630 $role_meta->get_required_method_list
629 map { $_->name } $role_meta->get_required_method_list,
631630 );
632631 }
633632 }
44
55 use Class::MOP;
66
7 our $VERSION = '0.79';
7 our $VERSION = '0.80';
88 $VERSION = eval $VERSION;
99 our $AUTHORITY = 'cpan:STEVAN';
1010
1010 use List::MoreUtils qw( any all uniq first_index );
1111 use Scalar::Util 'weaken', 'blessed';
1212
13 our $VERSION = '0.79';
13 our $VERSION = '0.80';
1414 $VERSION = eval $VERSION;
1515 our $AUTHORITY = 'cpan:STEVAN';
1616
33 use strict;
44 use warnings;
55
6 our $VERSION = '0.79';
6 our $VERSION = '0.80';
77 $VERSION = eval $VERSION;
88 our $AUTHORITY = 'cpan:STEVAN';
99
33 use strict;
44 use warnings;
55
6 our $VERSION = '0.79';
6 our $VERSION = '0.80';
77 $VERSION = eval $VERSION;
88 our $AUTHORITY = 'cpan:STEVAN';
99
290290
291291 =head1 DESCRIPTION
292292
293 This class is a subclass of L<Class::MOP::Class::Accessor> that
293 This class is a subclass of L<Class::MOP::Method::Accessor> that
294294 provides additional Moose-specific functionality, all of which is
295295 private.
296296
297297 To understand this class, you should read the the
298 L<Class::MOP::Class::Accessor> documentation.
298 L<Class::MOP::Method::Accessor> documentation.
299299
300300 =head1 BUGS
301301
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
55
66 use Scalar::Util 'blessed', 'weaken', 'looks_like_number', 'refaddr';
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 our $AUTHORITY = 'cpan:STEVAN';
1010
1111 use base 'Moose::Meta::Method',
66 use Carp 'confess';
77 use Scalar::Util 'blessed', 'weaken';
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
55
66 use Scalar::Util 'blessed', 'weaken';
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
5656 || $self->throw_error(
5757 "The is_needed method expected a metaclass object as its arugment");
5858
59 return $metaclass->find_method_by_name('DEMOLISH');
59 return $metaclass->find_method_by_name("DEMOLISHALL");
6060 }
6161
6262 sub initialize_body {
7777
7878 my @DEMOLISH_methods = $self->associated_metaclass->find_all_methods_by_name('DEMOLISH');
7979
80 return unless @DEMOLISH_methods;
80 my $source;
81 if ( @DEMOLISH_methods ) {
82 $source = 'sub {';
8183
82 my $source = 'sub {';
84 my @DEMOLISH_calls;
85 foreach my $method (@DEMOLISH_methods) {
86 push @DEMOLISH_calls => '$_[0]->' . $method->{class} . '::DEMOLISH()';
87 }
8388
84 my @DEMOLISH_calls;
85 foreach my $method (@DEMOLISH_methods) {
86 push @DEMOLISH_calls => '$_[0]->' . $method->{class} . '::DEMOLISH()';
89 $source .= join ";\n" => @DEMOLISH_calls;
90
91 $source .= ";\n" . '}';
92 } else {
93 $source = 'sub { }';
8794 }
8895
89 $source .= join ";\n" => @DEMOLISH_calls;
90
91 $source .= ";\n" . '}';
9296 warn $source if $self->options->{debug};
9397
9498 my $code = $self->_compile_code(
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
33 use warnings;
44 use metaclass;
55
6 use Scalar::Util 'blessed';
7 use List::MoreUtils qw(uniq);
6 use Scalar::Util 'blessed';
87
98 use Moose::Meta::Role::Composite;
109
11 our $VERSION = '0.79';
10 our $VERSION = '0.80';
1211 $VERSION = eval $VERSION;
1312 our $AUTHORITY = 'cpan:STEVAN';
1413
8887 sub check_required_methods {
8988 my ($self, $c) = @_;
9089
91 my %all_required_methods = map { $_ => undef } uniq(map {
92 $_->get_required_method_list
93 } @{$c->get_roles});
90 my %all_required_methods =
91 map { $_->name => $_ }
92 map { $_->get_required_method_list }
93 @{$c->get_roles};
9494
9595 foreach my $role (@{$c->get_roles}) {
9696 foreach my $required (keys %all_required_methods) {
101101 }
102102 }
103103
104 $c->add_required_methods(keys %all_required_methods);
104 $c->add_required_methods(values %all_required_methods);
105105 }
106106
107107 sub check_required_attributes {
166166
167167 my (%seen, %method_map);
168168 foreach my $method (@all_methods) {
169 if (exists $seen{$method->{name}}) {
170 if ($seen{$method->{name}}->body != $method->{method}->body) {
171 $c->add_required_methods($method->{name});
169 my $seen = $seen{$method->{name}};
170
171 if ($seen) {
172 if ($seen->{method}->body != $method->{method}->body) {
173 $c->add_conflicting_method(
174 name => $method->{name},
175 roles => [$method->{role}->name, $seen->{role}->name],
176 );
177
172178 delete $method_map{$method->{name}};
173179 next;
174180 }
175181 }
176182
177 $seen{$method->{name}} = $method->{method};
183 $seen{$method->{name}} = $method;
178184 $method_map{$method->{name}} = $method->{method};
179185 }
180186
66 use Moose::Util 'english_list';
77 use Scalar::Util 'weaken', 'blessed';
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
5757 # attribute accessors. However I am thinking
5858 # that maybe those are somehow exempt from
5959 # the require methods stuff.
60 foreach my $required_method_name ($role->get_required_method_list) {
60 foreach my $required_method ($role->get_required_method_list) {
61 my $required_method_name = $required_method->name;
6162
6263 if (!$class->find_method_by_name($required_method_name)) {
6364
6465 next if $self->is_aliased_method($required_method_name);
6566
66 push @missing, $required_method_name;
67 push @missing, $required_method;
6768 }
6869 }
6970
7172
7273 my $error = '';
7374
74 if (@missing) {
75 my @conflicts = grep { $_->isa('Moose::Meta::Role::Method::Conflicting') } @missing;
76
77 if (@conflicts) {
78 my $conflict = $conflicts[0];
79 my $roles = Moose::Util::english_list( map { q{'} . $_ . q{'} } @{ $conflict->roles } );
80
81 $error
82 .= "Due to a method name conflict in roles "
83 . $roles
84 . ", the method '"
85 . $conflict->name
86 . "' must be implemented or excluded by '"
87 . $class->name
88 . q{'};
89 }
90 elsif (@missing) {
7591 my $noun = @missing == 1 ? 'method' : 'methods';
7692
7793 my $list
55
66 use Scalar::Util 'blessed';
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
55
66 use Scalar::Util 'blessed';
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
3434
3535 sub check_required_methods {
3636 my ($self, $role1, $role2) = @_;
37 foreach my $required_method_name ($role1->get_required_method_list) {
37 foreach my $required_method ($role1->get_required_method_list) {
38 my $required_method_name = $required_method->name;
3839
3940 next if $self->is_aliased_method($required_method_name);
4041
41 $role2->add_required_methods($required_method_name)
42 $role2->add_required_methods($required_method)
4243 unless $role2->find_method_by_name($required_method_name);
4344 }
4445 }
104105 $role2->get_method($method_name)->body != $role1->get_method($method_name)->body) {
105106 # method conflicts between roles result
106107 # in the method becoming a requirement
107 $role2->add_required_methods($method_name);
108 $role2->add_conflicting_method(
109 name => $method_name,
110 roles => [$role1->name, $role2->name],
111 );
108112 }
109113 else {
110114 # add it, although it could be overridden
33 use warnings;
44 use metaclass;
55
6 our $VERSION = '0.79';
6 our $VERSION = '0.80';
77 $VERSION = eval $VERSION;
88 our $AUTHORITY = 'cpan:STEVAN';
99
55
66 use Scalar::Util 'blessed';
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
0
1 package Moose::Meta::Role::Method::Conflicting;
2
3 use strict;
4 use warnings;
5
6 use base qw(Moose::Meta::Role::Method::Required);
7
8 our $VERSION = '0.80';
9 $VERSION = eval $VERSION;
10 our $AUTHORITY = 'cpan:STEVAN';
11
12 __PACKAGE__->meta->add_attribute('roles' => (
13 reader => 'roles',
14 required => 1,
15 ));
16
17 1;
18
19 __END__
20
21 =pod
22
23 =head1 NAME
24
25 Moose::Meta::Role::Method::Conflicting - A Moose metaclass for conflicting methods in Roles
26
27 =head1 DESCRIPTION
28
29 =head1 INHERITANCE
30
31 C<Moose::Meta::Role::Method::Conflicting> is a subclass of
32 L<Moose::Meta::Role::Method::Required>.
33
34 =head1 METHODS
35
36 =over 4
37
38 =item B<< Moose::Meta::Role::Method::Conflicting->new(%options) >>
39
40 This creates a new type constraint based on the provided C<%options>:
41
42 =over 8
43
44 =item * name
45
46 The method name. This is required.
47
48 =item * roles
49
50 The list of role names that generated the conflict. This is required.
51
52 =back
53
54 =item B<< $method->name >>
55
56 Returns the conflicting method's name, as provided to the constructor.
57
58 =item B<< $method->roles >>
59
60 Returns the roles that generated this conflicting method, as provided to the
61 constructor.
62
63 =back
64
65 =head1 BUGS
66
67 All complex software has bugs lurking in it, and this module is no
68 exception. If you find a bug please either email me, or add the bug
69 to cpan-RT.
70
71 =head1 AUTHOR
72
73 Stevan Little E<lt>stevan@iinteractive.comE<gt>
74
75 =head1 COPYRIGHT AND LICENSE
76
77 Copyright 2006-2009 by Infinity Interactive, Inc.
78
79 L<http://www.iinteractive.com>
80
81 This library is free software; you can redistribute it and/or modify
82 it under the same terms as Perl itself.
83
84 =cut
22
33 use strict;
44 use warnings;
5 use metaclass;
56
6 our $VERSION = '0.79';
7 use overload '""' => sub { shift->name }, # stringify to method name
8 fallback => 1;
9
10 use base qw(Class::MOP::Object);
11
12 our $VERSION = '0.80';
713 $VERSION = eval $VERSION;
814 our $AUTHORITY = 'cpan:STEVAN';
915
10 use base 'Moose::Meta::Role::Method';
16 # This is not a Moose::Meta::Role::Method because it has no implementation, it
17 # is just a name
18
19 __PACKAGE__->meta->add_attribute('name' => (
20 reader => 'name',
21 required => 1,
22 ));
23
24 sub new { shift->_new(@_) }
1125
1226 1;
1327
2034 Moose::Meta::Role::Method::Required - A Moose metaclass for required methods in Roles
2135
2236 =head1 DESCRIPTION
37
38 =head1 INHERITANCE
39
40 C<Moose::Meta::Role::Method::Required> is a subclass of L<Class::MOP::Object>.
41 It is B<not> a subclass of C<Moose::Meta::Role::Method> since it does not
42 provide an implementation of the method.
43
44 =head1 METHODS
45
46 =over 4
47
48 =item B<< Moose::Meta::Role::Method::Required->new(%options) >>
49
50 This creates a new type constraint based on the provided C<%options>:
51
52 =over 8
53
54 =item * name
55
56 The method name. This is required.
57
58 =back
59
60 =item B<< $method->name >>
61
62 Returns the required method's name, as provided to the constructor.
63
64 =back
2365
2466 =head1 BUGS
2567
33 use strict;
44 use warnings;
55
6 our $VERSION = '0.79';
6 our $VERSION = '0.80';
77 $VERSION = eval $VERSION;
88 our $AUTHORITY = 'cpan:STEVAN';
99
99 use Sub::Name 'subname';
1010 use Devel::GlobalDestruction 'in_global_destruction';
1111
12 our $VERSION = '0.79';
12 our $VERSION = '0.80';
1313 $VERSION = eval $VERSION;
1414 our $AUTHORITY = 'cpan:STEVAN';
1515
1616 use Moose::Meta::Class;
1717 use Moose::Meta::Role::Method;
1818 use Moose::Meta::Role::Method::Required;
19 use Moose::Meta::Role::Method::Conflicting;
1920
2021 use base 'Class::MOP::Module';
2122
5657 attr_reader => 'get_excluded_roles_map' ,
5758 methods => {
5859 add => 'add_excluded_roles',
59 get_list => 'get_excluded_roles_list',
60 get_keys => 'get_excluded_roles_list',
6061 existence => 'excludes_role',
6162 }
6263 },
6465 name => 'required_methods',
6566 attr_reader => 'get_required_methods_map',
6667 methods => {
67 add => 'add_required_methods',
68 remove => 'remove_required_methods',
69 get_list => 'get_required_method_list',
70 existence => 'requires_method',
68 remove => 'remove_required_methods',
69 get_values => 'get_required_method_list',
70 existence => 'requires_method',
7171 }
7272 },
7373 {
7575 attr_reader => 'get_attribute_map',
7676 methods => {
7777 get => 'get_attribute',
78 get_list => 'get_attribute_list',
78 get_keys => 'get_attribute_list',
7979 existence => 'has_attribute',
8080 remove => 'remove_attribute',
8181 }
9797 $self->$attr_reader->{$_} = undef foreach @values;
9898 }) if exists $methods->{add};
9999
100 $META->add_method($methods->{get_list} => sub {
100 $META->add_method($methods->{get_keys} => sub {
101101 my ($self) = @_;
102102 keys %{$self->$attr_reader};
103 }) if exists $methods->{get_list};
103 }) if exists $methods->{get_keys};
104
105 $META->add_method($methods->{get_values} => sub {
106 my ($self) = @_;
107 values %{$self->$attr_reader};
108 }) if exists $methods->{get_values};
104109
105110 $META->add_method($methods->{get} => sub {
106111 my ($self, $name) = @_;
122127 'method_metaclass',
123128 reader => 'method_metaclass',
124129 default => 'Moose::Meta::Role::Method',
130 );
131
132 $META->add_attribute(
133 'required_method_metaclass',
134 reader => 'required_method_metaclass',
135 default => 'Moose::Meta::Role::Method::Required',
136 );
137
138 $META->add_attribute(
139 'conflicting_method_metaclass',
140 reader => 'conflicting_method_metaclass',
141 default => 'Moose::Meta::Role::Method::Conflicting',
125142 );
126143
127144 ## some things don't always fit, so they go here ...
141158 $attr_desc = { @_ };
142159 }
143160 $self->get_attribute_map->{$name} = $attr_desc;
161 }
162
163 sub add_required_methods {
164 my $self = shift;
165
166 for (@_) {
167 my $method = $_;
168 if (!blessed($method)) {
169 $method = $self->required_method_metaclass->new(
170 name => $method,
171 );
172 }
173 $self->get_required_methods_map->{$method->name} = $method;
174 }
175 }
176
177 sub add_conflicting_method {
178 my $self = shift;
179
180 my $method;
181 if (@_ == 1 && blessed($_[0])) {
182 $method = shift;
183 }
184 else {
185 $method = $self->conflicting_method_metaclass->new(@_);
186 }
187
188 $self->add_required_methods($method);
144189 }
145190
146191 ## ------------------------------------------------------------------
600645 # has 'roles' => (
601646 # metaclass => 'Collection::Array',
602647 # reader => 'get_roles',
603 # isa => 'ArrayRef[Moose::Meta::Roles]',
648 # isa => 'ArrayRef[Moose::Meta::Role]',
604649 # default => sub { [] },
605650 # provides => {
606651 # 'push' => 'add_role',
636681 # has 'required_methods' => (
637682 # metaclass => 'Collection::Hash',
638683 # reader => 'get_required_methods_map',
639 # isa => 'HashRef[Str]',
684 # isa => 'HashRef[Moose::Meta::Role::Method::Required]',
640685 # provides => {
641686 # # not exactly set, or delete since it works for multiple
642687 # 'set' => 'add_required_methods',
897942
898943 Returns true if the role requires the named method.
899944
900 =item B<< $metarole->add_required_methods(@names >>
901
902 Adds the named methods to the roles list of required methods.
945 =item B<< $metarole->add_required_methods(@names) >>
946
947 Adds the named methods to the role's list of required methods.
903948
904949 =item B<< $metarole->remove_required_methods(@names) >>
905950
906 Removes the named methods to the roles list of required methods.
951 Removes the named methods from the role's list of required methods.
952
953 =item B<< $metarole->add_conflicting_method(%params) >>
954
955 Instantiate the parameters as a L<Moose::Meta::Role::Method::Conflicting>
956 object, then add it to the required method list.
907957
908958 =back
909959
66
77 use Scalar::Util 'blessed';
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
77 use Moose::Meta::Attribute;
88 use Moose::Util::TypeConstraints ();
99
10 our $VERSION = '0.79';
10 our $VERSION = '0.80';
1111 $VERSION = eval $VERSION;
1212 our $AUTHORITY = 'cpan:STEVAN';
1313
66 use Scalar::Util 'blessed';
77 use Moose::Util::TypeConstraints ();
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
55
66 use Moose::Util::TypeConstraints ();
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
33 use warnings;
44 use metaclass;
55
6 our $VERSION = '0.79';
6 our $VERSION = '0.80';
77 $VERSION = eval $VERSION;
88 our $AUTHORITY = 'cpan:STEVAN';
99
77 use Moose::Util::TypeConstraints;
88 use Moose::Meta::TypeConstraint::Parameterizable;
99
10 our $VERSION = '0.79';
10 our $VERSION = '0.80';
1111 $VERSION = eval $VERSION;
1212 our $AUTHORITY = 'cpan:STEVAN';
1313
66
77 use Scalar::Util 'blessed';
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
66 use Scalar::Util 'blessed';
77 use Moose::Util::TypeConstraints ();
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
66
77 use Moose::Meta::TypeCoercion::Union;
88
9 our $VERSION = '0.79';
9 our $VERSION = '0.80';
1010 $VERSION = eval $VERSION;
1111 our $AUTHORITY = 'cpan:STEVAN';
1212
1212
1313 use base qw(Class::MOP::Object);
1414
15 our $VERSION = '0.79';
15 our $VERSION = '0.80';
1616 $VERSION = eval $VERSION;
1717 our $AUTHORITY = 'cpan:STEVAN';
1818
1010 use if ( not our $__mx_is_compiled ), 'Moose::Meta::Class';
1111 use if ( not our $__mx_is_compiled ), metaclass => 'Moose::Meta::Class';
1212
13 our $VERSION = '0.79';
13 our $VERSION = '0.80';
1414 $VERSION = eval $VERSION;
1515 our $AUTHORITY = 'cpan:STEVAN';
1616
55
66 use Sub::Exporter;
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
1717 use Moose::Util::TypeConstraints;
1818
1919 sub extends {
20 croak "Roles do not currently support 'extends'";
20 croak "Roles do not support 'extends' (you can use 'with' to specialize a role)";
2121 }
2222
2323 sub with {
173173
174174 =head1 DESCRIPTION
175175
176 Role support in Moose is pretty solid at this point. However, the best
177 documentation is still the the test suite. It is fairly safe to assume Perl 6
178 style behavior and then either refer to the test suite, or ask questions on
179 #moose if something doesn't quite do what you expect.
180
181 We are planning writing some more documentation in the near future, but nothing
182 is ready yet, sorry.
176 The concept of roles is documented in L<Moose::Manual::Role>. This document
177 serves as API documentation.
183178
184179 =head1 EXPORTED FUNCTIONS
185180
22 use strict;
33 use warnings;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
151151
152152 =head1 DESCRIPTION
153153
154 B<The whole concept behind this module is still considered
155 experimental, and it could go away in the future!>
156
157154 This utility module is designed to help authors of Moose extensions
158155 write extensions that are able to cooperate with other Moose
159156 extensions. To do this, you must write your extensions as roles, which
55 use Class::MOP;
66 use Scalar::Util 'blessed', 'looks_like_number';
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
55 use Scalar::Util qw( blessed reftype );
66 use Moose::Exporter;
77
8 our $VERSION = '0.79';
8 our $VERSION = '0.80';
99 $VERSION = eval $VERSION;
1010 our $AUTHORITY = 'cpan:STEVAN';
1111
505505 my $type = find_type_constraint($type_name);
506506 ( defined $type )
507507 || __PACKAGE__->_throw_error(
508 "Cannot find type '$type_name', perhaps you forgot to load it.");
508 "Cannot find type '$type_name', perhaps you forgot to load it");
509509 if ( $type->has_coercion ) {
510510 $type->coercion->add_type_coercions(@$coercion_map);
511511 }
77 use Scalar::Util 'blessed';
88 use Class::MOP 0.60;
99
10 our $VERSION = '0.79';
10 our $VERSION = '0.80';
1111 $VERSION = eval $VERSION;
1212 our $AUTHORITY = 'cpan:STEVAN';
1313
22
33 use 5.008;
44
5 our $VERSION = '0.79';
5 our $VERSION = '0.80';
66 $VERSION = eval $VERSION;
77 our $AUTHORITY = 'cpan:STEVAN';
88
6666 my $name = shift;
6767
6868 Moose->throw_error('Usage: has \'name\' => ( key => value, ... )')
69 if @_ == 1;
69 if @_ % 2 == 1;
7070
7171 my %options = ( definition_context => _caller_info(), @_ );
7272 my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ];
208208 my $method_meta = $class->meta;
209209
210210 ( blessed($method_meta) && $method_meta->isa('Moose::Meta::Class') )
211 || Moose->throw_error("$class already has a &meta function, but it does not return a Moose::Meta::Class ($meta)");
211 || Moose->throw_error("$class already has a &meta function, but it does not return a Moose::Meta::Class ($method_meta)");
212212
213213 $meta = $method_meta;
214214 }
263263 Moose::Meta::Role
264264 Moose::Meta::Role::Method
265265 Moose::Meta::Role::Method::Required
266 Moose::Meta::Role::Method::Conflicting
266267
267268 Moose::Meta::Role::Composite
268269
436437
437438 =item I<required =E<gt> (1|0)>
438439
439 This marks the attribute as being required. This means a I<defined> value must be
440 supplied during class construction, and the attribute may never be set to
441 C<undef> with an accessor.
440 This marks the attribute as being required. This means a value must be
441 supplied during class construction, I<or> the attribute must be lazy
442 and have either a default or a builder. Note that c<required> does not
443 say anything about the attribute's value, which can be C<undef>.
442444
443445 =item I<weak_ref =E<gt> (1|0)>
444446
77
88 use Moose::Util 'does_role', 'find_meta';
99
10 our $VERSION = '0.79';
10 our $VERSION = '0.80';
1111 $VERSION = eval $VERSION;
1212 our $AUTHORITY = 'cpan:STEVAN';
1313
44
55 use Class::MOP;
66
7 our $VERSION = '0.79';
7 our $VERSION = '0.80';
88 $VERSION = eval $VERSION;
99 our $AUTHORITY = 'cpan:STEVAN';
1010
214214 my $_foo_attr = $meta->get_attribute("_foo");
215215
216216 ok($foo_attr->is_lazy, "foo is lazy");
217 ok($foo_attr->is_required, "foo is required");
218217 ok($foo_attr->is_lazy_build, "foo is lazy_build");
219218
220219 ok($foo_attr->has_clearer, "foo has clearer");
227226 is($foo_attr->predicate, "has_foo", ".. and it's named has_foo");
228227
229228 ok($_foo_attr->is_lazy, "_foo is lazy");
230 ok($_foo_attr->is_required, "_foo is required");
229 ok(!$_foo_attr->is_required, "lazy_build attributes are no longer automatically required");
231230 ok($_foo_attr->is_lazy_build, "_foo is lazy_build");
232231
233232 ok($_foo_attr->has_clearer, "_foo has clearer");
261260
262261 ok(OutOfClassTest->meta->get_attribute('foo'), 'attr created from sub call');
263262 ok(OutOfClassTest->meta->get_attribute('bar'), 'attr created from can');
263
264
265 {
266 {
267 package Foo;
268 use Moose;
269
270 ::throws_ok { has 'foo' => ( 'ro', isa => 'Str' ) }
271 qr/^Usage/, 'has throws error with odd number of attribute options';
272 }
273
274 }
22 use strict;
33 use warnings;
44
5 use Test::More tests => 87; # it's really 124 with kolibrie's tests;
5 use Test::More tests => 88;
66 use Test::Exception;
77
88 =pod
9999
100100 ::throws_ok {
101101 with 'Role::Bling', 'Role::Bling::Bling';
102 } qr/requires the method \'bling\' to be implemented/, '... role methods conflicted and method was required';
102 } qr/Due to a method name conflict in roles 'Role::Bling' and 'Role::Bling::Bling', the method 'bling' must be implemented or excluded by 'My::Test3'/, '... role methods conflict and method was required';
103103
104104 package My::Test4;
105105 use Moose;
189189 ::throws_ok {
190190 with 'Role::Boo', 'Role::Boo::Hoo';
191191 } qr/We have encountered an attribute conflict/,
192 '... role attrs conflicted and method was required';
192 '... role attrs conflict and method was required';
193193
194194 package My::Test8;
195195 use Moose;
215215 ::throws_ok {
216216 with 'Role::Boo', 'Role::Boo::Hoo';
217217 } qr/We have encountered an attribute conflict/,
218 '... role attrs conflicted and cannot be manually disambiguted';
218 '... role attrs conflict and cannot be manually disambiguted';
219219
220220 }
221221
342342 is(Role::Reality->meta->get_method('twist')->(),
343343 'Role::Reality::twist',
344344 '... the twist method returns the right value');
345
346 # Ovid's test case from rt.cpan.org #44
347 {
348 package Role1;
349 use Moose::Role;
350
351 sub foo {}
352 }
353 {
354 package Role2;
355 use Moose::Role;
356
357 sub foo {}
358 }
359 {
360 package Conflicts;
361 use Moose;
362
363 ::throws_ok {
364 with qw(Role1 Role2);
365 } qr/Due to a method name conflict in roles 'Role1' and 'Role2', the method 'foo' must be implemented or excluded by 'Conflicts'/;
366 }
345367
346368 =pod
347369
4848
4949 {
5050 # check that when a role is added to another role
51 # and they conflict and the method they conflicted
51 # and they conflict and the method they conflict
5252 # with is then required.
5353
5454 package Role::A::Conflict;
6363
6464 ::throws_ok {
6565 with 'Role::A::Conflict';
66 } qr/requires.*'bar'/, '... did not fufill the requirement of &bar method';
66 } qr/Due to a method name conflict in roles 'Role::A' and 'Role::A::Conflict', the method 'bar' must be implemented or excluded by 'Class::A::Conflict'/, '... did not fufill the requirement of &bar method';
6767
6868 package Class::A::Resolved;
6969 use Moose;
180180
181181 ::throws_ok {
182182 with qw(Role::I);
183 } qr/requires.*'foo'/, "defining class Class::C fails";
183 } qr/Due to a method name conflict in roles 'Role::H' and 'Role::J', the method 'foo' must be implemented or excluded by 'Class::C'/, "defining class Class::C fails";
184184
185185 sub zot { 'Class::C::zot' }
186186
7171 with 'Foo::Role',
7272 'Bar::Role' => { excludes => 'foo' },
7373 'Baz::Role';
74 } qr/\'Foo::Role\|Bar::Role\|Baz::Role\' requires the method \'foo\' to be implemented by \'My::Foo::Class::Broken\'/,
74 } qr/Due to a method name conflict in roles 'Baz::Role' and 'Foo::Role', the method 'foo' must be implemented or excluded by 'My::Foo::Class::Broken'/,
7575 '... composed our roles correctly';
7676 }
7777
104104 with 'Foo::Role' => { alias => { 'foo' => 'foo_foo' }, excludes => 'foo' },
105105 'Bar::Role' => { alias => { 'foo' => 'foo_foo' }, excludes => 'foo' },
106106 'Baz::Role';
107 } qr/\'Foo::Role\|Bar::Role\|Baz::Role\' requires the method \'foo_foo\' to be implemented by \'My::Foo::Class::Broken\'/,
107 } qr/Due to a method name conflict in roles 'Bar::Role' and 'Foo::Role', the method 'foo_foo' must be implemented or excluded by 'My::Foo::Class::Broken'/,
108108 '... composed our roles correctly';
109109 }
110110
22 use strict;
33 use warnings;
44
5 use Test::More tests => 16;
5 use Test::More tests => 17;
66
77
88 {
7070 'original fq name is Role::Foo::foo' );
7171 }
7272
73 is( ClassB->foo, 'ClassB::foo', 'ClassB::foo knows its name' );
73 isnt( ClassA->foo, "ClassB::foo", "ClassA::foo is not confused with ClassB::foo");
74
7475 {
7576 local $TODO =
7677 "multiply-consumed roles' subs take on their most recently used name";
78 is( ClassB->foo, 'ClassB::foo', 'ClassB::foo knows its name' );
7779 is( ClassA->foo, 'ClassA::foo', 'ClassA::foo knows its name' );
7880 }
77 BEGIN {
88 eval "use Test::Output;";
99 plan skip_all => "Test::Output is required for this test" if $@;
10 plan tests => 45;
10 plan tests => 47;
1111 }
1212
1313
215215 }
216216
217217 {
218 package MooseX::CircularAlso;
218 package MooseX::NoAlso;
219219
220220 use Moose ();
221221
230230
231231 ::like(
232232 $@,
233 qr/\QPackage in also (NoSuchThing) does not seem to use Moose::Exporter/,
233 qr/\QPackage in also (NoSuchThing) does not seem to use Moose::Exporter (is it loaded?) at /,
234 'got the expected error from a reference in also to a package which is not loaded'
235 );
236 }
237
238 {
239 package MooseX::NotExporter;
240
241 use Moose ();
242
243 ::dies_ok(
244 sub {
245 Moose::Exporter->setup_import_methods(
246 also => [ 'Moose::Meta::Method' ],
247 );
248 },
249 'a package which does not use Moose::Exporter in also dies with an error'
250 );
251
252 ::like(
253 $@,
254 qr/\QPackage in also (Moose::Meta::Method) does not seem to use Moose::Exporter at /,
234255 'got the expected error from a reference in also to a package which does not use Moose::Exporter'
235256 );
236257 }
1010
1111 package main;
1212
13 use Test::More tests => 2;
13 use Test::More tests => 4;
1414
1515 {
16 local $TODO = 'for rafl';
16 local $TODO = 'Role composition does not clone methods yet';
1717 is(MyClass1->foo, 'MyClass1::foo',
1818 'method from role has correct name in caller()');
19 is(MyClass2->foo, 'MyClass2::foo',
20 'method from role has correct name in caller()');
1921 }
20 is(MyClass2->foo, 'MyClass2::foo');
22
23 isnt(MyClass1->foo, "MyClass2::foo", "role method is not confused with other class" );
24 isnt(MyClass2->foo, "MyClass1::foo", "role method is not confused with other class" );
0 use strict;
1 use warnings;
2 use Test::More tests => 10;
3
4 {
5 package Ball;
6 use Moose;
7 }
8
9 {
10 package Arbitrary::Roll;
11 use Moose::Role;
12 }
13
14 my $method_meta = Moose::Meta::Class->create_anon_class(
15 superclasses => ['Moose::Meta::Method'],
16 roles => ['Arbitrary::Roll'],
17 );
18
19 # For comparing identity without actually keeping $original_meta around
20 my $original_meta = "$method_meta";
21
22 my $method_class = $method_meta->name;
23
24 my $method_object = $method_class->wrap(
25 sub {'ok'},
26 associated_metaclass => Ball->meta,
27 package_name => 'Ball',
28 name => 'bounce',
29 );
30
31 Ball->meta->add_method( bounce => $method_object );
32
33 for ( 1, 2 ) {
34 is( Ball->bounce, 'ok', "method still exists on Ball" );
35 is( Ball->meta->get_method('bounce')->meta->name, $method_class,
36 "method's package still exists" );
37
38 is( Ball->meta->get_method('bounce'), $method_object,
39 'original method object is preserved' );
40
41 local $TODO = "method metaclass seems to be reinitialized" if !$method_meta;
42
43 is( Ball->meta->get_method('bounce')->meta . '', $original_meta,
44 "method's metaclass still exists" );
45 ok( Ball->meta->get_method('bounce')->meta->does_role('Arbitrary::Roll'),
46 "method still does Arbitrary::Roll" );
47
48 undef $method_meta;
49 }
0 use strict;
1 use warnings;
2
3 use Test::Exception;
4 use Test::More tests => 2;
5
6 {
7
8 package FakeBar;
9 use Moose::Role;
10
11 around isa => sub {
12 my ( $orig, $self, $v ) = @_;
13 return 1 if $v eq 'Bar';
14 return $orig->( $self, $v );
15 };
16
17 package Foo;
18 use Moose;
19
20 use Test::More; # for $TODO
21
22 local $TODO = 'UNIVERSAL methods should be wrappable';
23
24 ::lives_ok { with 'FakeBar' } 'applied role';
25
26 my $foo = Foo->new;
27 ::isa_ok $foo, 'Bar';
28 }
0 use strict;
1 use warnings;
2
3 use Test::More tests => 1;
4 use Test::Exception;
5
6 use Moose::Meta::Class;
7
8 $SIG{__WARN__} = sub { die if shift =~ /recurs/ };
9
10 TODO:
11 {
12 local $TODO
13 = 'Loading Moose::Meta::Class without loading Moose.pm causes weird problems';
14
15 my $meta;
16 lives_ok {
17 $meta = Moose::Meta::Class->create_anon_class(
18 superclasses => [ 'Moose::Object', ],
19 );
20 }
21 'Class is created successfully';
22 }
0 #!/usr/bin/env perl
1 use strict;
2 use warnings;
3 use Test::More tests => 10;
4
5 {
6 package FooTrait;
7 use Moose::Role;
8 }
9 {
10 package Foo;
11 use Moose -traits => ['FooTrait'];
12 }
13
14 is(Class::MOP::class_of('Foo'), Foo->meta,
15 "class_of and ->meta are the same on Foo");
16 my $meta = Foo->meta;
17 is(Class::MOP::class_of($meta), $meta->meta,
18 "class_of and ->meta are the same on Foo's metaclass");
19 isa_ok(Class::MOP::class_of($meta), 'Moose::Meta::Class');
20 isa_ok($meta->meta, 'Moose::Meta::Class');
21 Foo->meta->make_immutable;
22 is(Class::MOP::class_of('Foo'), Foo->meta,
23 "class_of and ->meta are the same on Foo (immutable)");
24 $meta = Foo->meta;
25 isa_ok($meta->meta, 'Moose::Meta::Class');
26 ok(Class::MOP::class_of($meta)->is_immutable, "metaclass is immutable");
27 TODO: {
28 local $TODO = "immutable metaclasses with traits do weird things";
29 is(Class::MOP::class_of($meta), $meta->meta,
30 "class_of and ->meta are the same on Foo's metaclass (immutable)");
31 isa_ok(Class::MOP::class_of($meta), 'Moose::Meta::Class');
32 ok($meta->meta->is_immutable, "metaclass is immutable");
33 }
0 #!/usr/bin/perl
1
2 use strict;
3 use warnings;
4
5 use Test::More tests => 39;
6 use Test::Exception;
7
8 sub req_or_has ($$) {
9 my ( $role, $method ) = @_;
10 local $Test::Builder::Level = $Test::Builder::Level + 1;
11 if ( $role ) {
12 ok(
13 $role->has_method($method) || $role->requires_method($method),
14 $role->name . " has or requires method $method"
15 );
16 } else {
17 fail("role has or requires method $method");
18 }
19 }
20
21 {
22 package Bar;
23 use Moose::Role;
24
25 # this role eventually adds three methods, qw(foo bar xxy), but only one is
26 # known when it's still a role
27
28 has foo => ( is => "rw" );
29
30 has gorch => ( reader => "bar" );
31
32 sub xxy { "BAAAD" }
33
34 package Gorch;
35 use Moose::Role;
36
37 # similarly this role gives attr and gorch_method
38
39 has attr => ( is => "rw" );
40
41 sub gorch_method { "gorch method" }
42
43 around dandy => sub { shift->(@_) . "bar" };
44
45 package Quxx;
46 use Moose;
47
48 sub dandy { "foo" }
49
50 # this object will be used in an attr of Foo to test that Foo can do the
51 # Gorch interface
52
53 with qw(Gorch);
54
55 package Dancer;
56 use Moose::Role;
57
58 requires "twist";
59
60 package Dancer::Ballerina;
61 use Moose;
62
63 with qw(Dancer);
64
65 sub twist { }
66
67 sub pirouette { }
68
69 package Dancer::Robot;
70 use Moose::Role;
71
72 # this doesn't fail but it produces a requires in the role
73 # the order doesn't matter
74 has twist => ( is => "rw" );
75 ::lives_ok { with qw(Dancer) };
76
77 package Dancer::Something;
78 use Moose;
79
80 # this fail even though the method already exists
81
82 has twist => ( is => "rw" );
83
84 {
85 ::lives_ok { with qw(Dancer) };
86 }
87
88 package Dancer::80s;
89 use Moose;
90
91 # this should pass because ::Robot has the attribute to fill in the requires
92 # but due to the deferrence logic that doesn't actually work
93 {
94 local our $TODO = "attribute accessor in role doesn't satisfy role requires";
95 ::lives_ok { with qw(Dancer::Robot) };
96 }
97
98 package Foo;
99 use Moose;
100
101 with qw(Bar);
102
103 has oink => (
104 is => "rw",
105 handles => "Gorch", # should handles take the same arguments as 'with'? Meta::Role::Application::Delegation?
106 default => sub { Quxx->new },
107 );
108
109 has dancer => (
110 is => "rw",
111 does => "Dancer",
112 handles => "Dancer",
113 default => sub { Dancer::Ballerina->new },
114 );
115
116 sub foo { 42 }
117
118 sub bar { 33 }
119
120 sub xxy { 7 }
121
122 package Tree;
123 use Moose::Role;
124
125 has bark => ( is => "rw" );
126
127 package Dog;
128 use Moose::Role;
129
130 sub bark { warn "woof!" };
131
132 package EntPuppy;
133 use Moose;
134
135 {
136 local our $TODO = "attrs and methods from a role should clash";
137 ::dies_ok { with qw(Tree Dog) }
138 }
139 }
140
141 # these fail because of the deferral logic winning over actual methods
142 # this might be tricky to fix due to the 'sub foo {}; has foo => ( )' hack
143 # we've been doing for a long while, though I doubt people relied on it for
144 # anything other than fulfilling 'requires'
145 {
146 local $TODO = "attributes from role overwrite class methods";
147 is( Foo->new->foo, 42, "attr did not zap overriding method" );
148 is( Foo->new->bar, 33, "attr did not zap overriding method" );
149 }
150 is( Foo->new->xxy, 7, "method did not zap overriding method" ); # duh
151
152 # these pass, simple delegate
153 # mostly they are here to contrast the next blck
154 can_ok( Foo->new->oink, "dandy" );
155 can_ok( Foo->new->oink, "attr" );
156 can_ok( Foo->new->oink, "gorch_method" );
157
158 ok( Foo->new->oink->does("Gorch"), "Quxx does Gorch" );
159
160
161 # these are broken because 'attr' is not technically part of the interface
162 can_ok( Foo->new, "gorch_method" );
163 {
164 local $TODO = "accessor methods from a role are omitted in handles role";
165 can_ok( Foo->new, "attr" );
166 }
167
168 {
169 local $TODO = "handles role doesn't add the role to the ->does of the delegate's parent class";
170 ok( Foo->new->does("Gorch"), "Foo does Gorch" );
171 }
172
173
174 # these work
175 can_ok( Foo->new->dancer, "pirouette" );
176 can_ok( Foo->new->dancer, "twist" );
177
178 can_ok( Foo->new, "twist" );
179 ok( !Foo->new->can("pirouette"), "can't pirouette, not part of the iface" );
180
181 {
182 local $TODO = "handles role doesn't add the role to the ->does of the delegate's parent class";
183 ok( Foo->new->does("Dancer") );
184 }
185
186
187
188
189 my $gorch = Gorch->meta;
190
191 isa_ok( $gorch, "Moose::Meta::Role" );
192
193 ok( $gorch->has_attribute("attr"), "has attribute 'attr'" );
194
195 {
196 local $TODO = "role attribute isn't a meta attribute yet";
197 isa_ok( $gorch->get_attribute("attr"), "Moose::Meta::Attribute" );
198 }
199
200 req_or_has($gorch, "gorch_method");
201 ok( $gorch->has_method("gorch_method"), "has_method gorch_method" );
202 ok( !$gorch->requires_method("gorch_method"), "requires gorch method" );
203 isa_ok( $gorch->get_method("gorch_method"), "Moose::Meta::Method" );
204
205 {
206 local $TODO = "method modifier doesn't yet create a method requirement or meta object";
207 req_or_has($gorch, "dandy" );
208
209 # this specific test is maybe not backwards compat, but in theory it *does*
210 # require that method to exist
211 ok( $gorch->requires_method("dandy"), "requires the dandy method for the modifier" );
212 }
213
214 {
215 local $TODO = "attribute related methods are not yet known by the role";
216 # we want this to be a part of the interface, somehow
217 req_or_has($gorch, "attr");
218 ok( $gorch->has_method("attr"), "has_method attr" );
219 isa_ok( $gorch->get_method("attr"), "Moose::Meta::Method" );
220 isa_ok( $gorch->get_method("attr"), "Moose::Meta::Method::Accessor" );
221 }
222
223 my $robot = Dancer::Robot->meta;
224
225 isa_ok( $robot, "Moose::Meta::Role" );
226
227 ok( $robot->has_attribute("twist"), "has attr 'twist'" );
228
229 {
230 local $TODO = "role attribute isn't a meta attribute yet";
231 isa_ok( $robot->get_attribute("twist"), "Moose::Meta::Attribute" );
232 }
233
234 {
235 req_or_has($robot, "twist");
236
237 local $TODO = "attribute related methods are not yet known by the role";
238 ok( $robot->has_method("twist"), "has twist method" );
239 isa_ok( $robot->get_method("twist"), "Moose::Meta::Method" );
240 isa_ok( $robot->get_method("twist"), "Moose::Meta::Method::Accessor" );
241 }
242
243 __END__
244
245 I think Attribute needs to be refactored in some way to better support roles.
246
247 There are several possible ways to do this, all of them seem plausible to me.
248
249 The first approach would be to change the attribute class to allow it to be
250 queried about the methods it would install.
251
252 Then we instantiate the attribute in the role, and instead of deferring the
253 arguments, we just make an C<unpack>ish method.
254
255 Then we can interrogate the attr when adding it to the role, and generate stub
256 methods for all the methods it would produce.
257
258 A second approach is kinda like the Immutable hack: wrap the attr in an
259 anonmyous class that disables part of its interface.
260
261 A third method would be to create an Attribute::Partial object that would
262 provide a more role-ish behavior, and to do this independently of the actual
263 Attribute class.
264
265 Something similar can be done for method modifiers, but I think that's even simpler.
266
267
268
269 The benefits of doing this are:
270
271 * Much better introspection of roles
272
273 * More correctness in many cases (in my opinion anyway)
274
275 * More roles are more usable as interface declarations, without having to split
276 them into two pieces (one for the interface with a bunch of requires(), and
277 another for the actual impl with the problematic attrs (and stub methods to
278 fix the accessors) and method modifiers (dunno if this can even work at all)
279
280
+0
-281
t/600_todo_tests/002_various_role_shit.t less more
0 #!/usr/bin/perl
1
2 use strict;
3 use warnings;
4
5 use Test::More tests => 39;
6 use Test::Exception;
7
8 sub req_or_has ($$) {
9 my ( $role, $method ) = @_;
10 local $Test::Builder::Level = $Test::Builder::Level + 1;
11 if ( $role ) {
12 ok(
13 $role->has_method($method) || $role->requires_method($method),
14 $role->name . " has or requires method $method"
15 );
16 } else {
17 fail("role has or requires method $method");
18 }
19 }
20
21 {
22 package Bar;
23 use Moose::Role;
24
25 # this role eventually adds three methods, qw(foo bar xxy), but only one is
26 # known when it's still a role
27
28 has foo => ( is => "rw" );
29
30 has gorch => ( reader => "bar" );
31
32 sub xxy { "BAAAD" }
33
34 package Gorch;
35 use Moose::Role;
36
37 # similarly this role gives attr and gorch_method
38
39 has attr => ( is => "rw" );
40
41 sub gorch_method { "gorch method" }
42
43 around dandy => sub { shift->(@_) . "bar" };
44
45 package Quxx;
46 use Moose;
47
48 sub dandy { "foo" }
49
50 # this object will be used in an attr of Foo to test that Foo can do the
51 # Gorch interface
52
53 with qw(Gorch);
54
55 package Dancer;
56 use Moose::Role;
57
58 requires "twist";
59
60 package Dancer::Ballerina;
61 use Moose;
62
63 with qw(Dancer);
64
65 sub twist { }
66
67 sub pirouette { }
68
69 package Dancer::Robot;
70 use Moose::Role;
71
72 # this doesn't fail but it produces a requires in the role
73 # the order doesn't matter
74 has twist => ( is => "rw" );
75 ::lives_ok { with qw(Dancer) };
76
77 package Dancer::Something;
78 use Moose;
79
80 # this fail even though the method already exists
81
82 has twist => ( is => "rw" );
83
84 {
85 ::lives_ok { with qw(Dancer) };
86 }
87
88 package Dancer::80s;
89 use Moose;
90
91 # this should pass because ::Robot has the attribute to fill in the requires
92 # but due to the deferrence logic that doesn't actually work
93 {
94 local our $TODO = "attribute accessor in role doesn't satisfy role requires";
95 ::lives_ok { with qw(Dancer::Robot) };
96 }
97
98 package Foo;
99 use Moose;
100
101 with qw(Bar);
102
103 has oink => (
104 is => "rw",
105 handles => "Gorch", # should handles take the same arguments as 'with'? Meta::Role::Application::Delegation?
106 default => sub { Quxx->new },
107 );
108
109 has dancer => (
110 is => "rw",
111 does => "Dancer",
112 handles => "Dancer",
113 default => sub { Dancer::Ballerina->new },
114 );
115
116 sub foo { 42 }
117
118 sub bar { 33 }
119
120 sub xxy { 7 }
121
122 package Tree;
123 use Moose::Role;
124
125 has bark => ( is => "rw" );
126
127 package Dog;
128 use Moose::Role;
129
130 sub bark { warn "woof!" };
131
132 package EntPuppy;
133 use Moose;
134
135 {
136 local our $TODO = "attrs and methods from a role should clash";
137 ::dies_ok { with qw(Tree Dog) }
138 }
139 }
140
141 # these fail because of the deferral logic winning over actual methods
142 # this might be tricky to fix due to the 'sub foo {}; has foo => ( )' hack
143 # we've been doing for a long while, though I doubt people relied on it for
144 # anything other than fulfilling 'requires'
145 {
146 local $TODO = "attributes from role overwrite class methods";
147 is( Foo->new->foo, 42, "attr did not zap overriding method" );
148 is( Foo->new->bar, 33, "attr did not zap overriding method" );
149 }
150 is( Foo->new->xxy, 7, "method did not zap overriding method" ); # duh
151
152 # these pass, simple delegate
153 # mostly they are here to contrast the next blck
154 can_ok( Foo->new->oink, "dandy" );
155 can_ok( Foo->new->oink, "attr" );
156 can_ok( Foo->new->oink, "gorch_method" );
157
158 ok( Foo->new->oink->does("Gorch"), "Quxx does Gorch" );
159
160
161 # these are broken because 'attr' is not technically part of the interface
162 can_ok( Foo->new, "gorch_method" );
163 {
164 local $TODO = "accessor methods from a role are omitted in handles role";
165 can_ok( Foo->new, "attr" );
166 }
167
168 {
169 local $TODO = "handles role doesn't add the role to the ->does of the delegate's parent class";
170 ok( Foo->new->does("Gorch"), "Foo does Gorch" );
171 }
172
173
174 # these work
175 can_ok( Foo->new->dancer, "pirouette" );
176 can_ok( Foo->new->dancer, "twist" );
177
178 can_ok( Foo->new, "twist" );
179 ok( !Foo->new->can("pirouette"), "can't pirouette, not part of the iface" );
180
181 {
182 local $TODO = "handles role doesn't add the role to the ->does of the delegate's parent class";
183 ok( Foo->new->does("Dancer") );
184 }
185
186
187
188
189 my $gorch = Gorch->meta;
190
191 isa_ok( $gorch, "Moose::Meta::Role" );
192
193 ok( $gorch->has_attribute("attr"), "has attribute 'attr'" );
194
195 {
196 local $TODO = "role attribute isn't a meta attribute yet";
197 isa_ok( $gorch->get_attribute("attr"), "Moose::Meta::Attribute" );
198 }
199
200 req_or_has($gorch, "gorch_method");
201 ok( $gorch->has_method("gorch_method"), "has_method gorch_method" );
202 ok( !$gorch->requires_method("gorch_method"), "requires gorch method" );
203 isa_ok( $gorch->get_method("gorch_method"), "Moose::Meta::Method" );
204
205 {
206 local $TODO = "method modifier doesn't yet create a method requirement or meta object";
207 req_or_has($gorch, "dandy" );
208
209 # this specific test is maybe not backwards compat, but in theory it *does*
210 # require that method to exist
211 ok( $gorch->requires_method("dandy"), "requires the dandy method for the modifier" );
212 }
213
214 {
215 local $TODO = "attribute related methods are not yet known by the role";
216 # we want this to be a part of the interface, somehow
217 req_or_has($gorch, "attr");
218 ok( $gorch->has_method("attr"), "has_method attr" );
219 isa_ok( $gorch->get_method("attr"), "Moose::Meta::Method" );
220 isa_ok( $gorch->get_method("attr"), "Moose::Meta::Method::Accessor" );
221 }
222
223 my $robot = Dancer::Robot->meta;
224
225 isa_ok( $robot, "Moose::Meta::Role" );
226
227 ok( $robot->has_attribute("twist"), "has attr 'twist'" );
228
229 {
230 local $TODO = "role attribute isn't a meta attribute yet";
231 isa_ok( $robot->get_attribute("twist"), "Moose::Meta::Attribute" );
232 }
233
234 {
235 req_or_has($robot, "twist");
236
237 local $TODO = "attribute related methods are not yet known by the role";
238 ok( $robot->has_method("twist"), "has twist method" );
239 isa_ok( $robot->get_method("twist"), "Moose::Meta::Method" );
240 isa_ok( $robot->get_method("twist"), "Moose::Meta::Method::Accessor" );
241 }
242
243 __END__
244
245 I think Attribute needs to be refactored in some way to better support roles.
246
247 There are several possible ways to do this, all of them seem plausible to me.
248
249 The first approach would be to change the attribute class to allow it to be
250 queried about the methods it would install.
251
252 Then we instantiate the attribute in the role, and instead of deferring the
253 arguments, we just make an C<unpack>ish method.
254
255 Then we can interrogate the attr when adding it to the role, and generate stub
256 methods for all the methods it would produce.
257
258 A second approach is kinda like the Immutable hack: wrap the attr in an
259 anonmyous class that disables part of its interface.
260
261 A third method would be to create an Attribute::Partial object that would
262 provide a more role-ish behavior, and to do this independently of the actual
263 Attribute class.
264
265 Something similar can be done for method modifiers, but I think that's even simpler.
266
267
268
269 The benefits of doing this are:
270
271 * Much better introspection of roles
272
273 * More correctness in many cases (in my opinion anyway)
274
275 * More roles are more usable as interface declarations, without having to split
276 them into two pieces (one for the interface with a bunch of requires(), and
277 another for the actual impl with the problematic attrs (and stub methods to
278 fix the accessors) and method modifiers (dunno if this can even work at all)
279
280
151151 runtime
152152 stacktrace
153153 subclassable
154 subname
154155 subtyping
155156 TODO
156157 unblessed