Test is_subtype_of on role_type of undefined role
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint / Role.pm
CommitLineData
620db045 1package Moose::Meta::TypeConstraint::Role;
2
3use strict;
4use warnings;
5use metaclass;
6
089455fc 7use B;
620db045 8use Scalar::Util 'blessed';
9use Moose::Util::TypeConstraints ();
10
620db045 11use base 'Moose::Meta::TypeConstraint';
12
13__PACKAGE__->meta->add_attribute('role' => (
14 reader => 'role',
dc2b7cc8 15 Class::MOP::_definition_context(),
620db045 16));
17
089455fc 18my $inliner = sub {
19 my $self = shift;
20 my $val = shift;
21
3975b592 22 return 'Moose::Util::does_role('
23 . $val . ', '
24 . B::perlstring($self->role)
25 . ')';
089455fc 26};
27
620db045 28sub new {
29 my ( $class, %args ) = @_;
30
f37d0936 31 $args{parent} = Moose::Util::TypeConstraints::find_type_constraint('Object');
7ae2d933 32
33 my $role_name = $args{role};
34 $args{constraint} = sub { Moose::Util::does_role( $_[0], $role_name ) };
35
089455fc 36 $args{inlined} = $inliner;
37
92a88343 38 my $self = $class->SUPER::new( \%args );
620db045 39
40 $self->_create_hand_optimized_type_constraint;
41 $self->compile_type_constraint();
42
43 return $self;
44}
45
46sub _create_hand_optimized_type_constraint {
47 my $self = shift;
48 my $role = $self->role;
49 $self->hand_optimized_type_constraint(
50 sub { Moose::Util::does_role($_[0], $role) }
51 );
52}
53
54sub parents {
55 my $self = shift;
56 return (
57 $self->parent,
58 map {
59 # FIXME find_type_constraint might find a TC named after the role but that isn't really it
60 # I did this anyway since it's a convention that preceded TypeConstraint::Role, and it should DWIM
61 # if anybody thinks this problematic please discuss on IRC.
62 # a possible fix is to add by attr indexing to the type registry to find types of a certain property
63 # regardless of their name
d03bd989 64 Moose::Util::TypeConstraints::find_type_constraint($_)
65 ||
620db045 66 __PACKAGE__->new( role => $_, name => "__ANON__" )
1551760b 67 } @{ Class::MOP::class_of($self->role)->get_roles },
620db045 68 );
69}
70
71sub equals {
72 my ( $self, $type_or_name ) = @_;
73
74 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
75
4c015454 76 return unless defined $other;
620db045 77 return unless $other->isa(__PACKAGE__);
78
79 return $self->role eq $other->role;
80}
81
82sub is_a_type_of {
83 my ($self, $type_or_name) = @_;
84
8d33489c 85 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
620db045 86
87 ($self->equals($type) || $self->is_subtype_of($type_or_name));
88}
89
90sub is_subtype_of {
91 my ($self, $type_or_name_or_role ) = @_;
92
93 if ( not ref $type_or_name_or_role ) {
94 # it might be a role
6f84b038 95 return 1 if Class::MOP::class_of($self->role)->does_role( $type_or_name_or_role );
620db045 96 }
97
98 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name_or_role);
99
4c015454 100 return unless defined $type;
d03bd989 101
620db045 102 if ( $type->isa(__PACKAGE__) ) {
103 # if $type_or_name_or_role isn't a role, it might be the TC name of another ::Role type
104 # or it could also just be a type object in this branch
db6ace79 105 return Class::MOP::class_of($self->role)->does_role( $type->role );
620db045 106 } else {
107 # the only other thing we are a subtype of is Object
108 $self->SUPER::is_subtype_of($type);
109 }
110}
111
2fb4885e 112sub create_child_type {
113 my ($self, @args) = @_;
39170e48 114 return Moose::Meta::TypeConstraint->new(@args, parent => $self);
2fb4885e 115}
116
620db045 1171;
118
ad46f524 119# ABSTRACT: Role/TypeConstraint parallel hierarchy
120
620db045 121__END__
122
123=pod
124
3cb26ff4 125=head1 DESCRIPTION
126
127This class represents type constraints for a role.
128
129=head1 INHERITANCE
130
131C<Moose::Meta::TypeConstraint::Role> is a subclass of
132L<Moose::Meta::TypeConstraint>.
133
620db045 134=head1 METHODS
135
136=over 4
137
3cb26ff4 138=item B<< Moose::Meta::TypeConstraint::Role->new(%options) >>
139
140This creates a new role type constraint based on the given
141C<%options>.
142
143It takes the same options as its parent, with two exceptions. First,
144it requires an additional option, C<role>, which is name of the
145constraint's role. Second, it automatically sets the parent to the
146C<Object> type.
147
148The constructor also overrides the hand optimized type constraint with
149one it creates internally.
620db045 150
3cb26ff4 151=item B<< $constraint->role >>
620db045 152
3cb26ff4 153Returns the role name associated with the constraint.
620db045 154
3cb26ff4 155=item B<< $constraint->parents >>
620db045 156
3cb26ff4 157Returns all the type's parent types, corresponding to the roles that
158its role does.
620db045 159
2870fb09 160=item B<< $constraint->is_subtype_of($type_name_or_object) >>
620db045 161
3cb26ff4 162If the given type is also a role type, then this checks that the
163type's role does the other type's role.
620db045 164
3cb26ff4 165Otherwise it falls back to the implementation in
166L<Moose::Meta::TypeConstraint>.
2fb4885e 167
3cb26ff4 168=item B<< $constraint->create_child_type(%options) >>
620db045 169
3cb26ff4 170This returns a new L<Moose::Meta::TypeConstraint> object with the type
171as its parent.
620db045 172
3cb26ff4 173Note that it does I<not> return a C<Moose::Meta::TypeConstraint::Role>
174object!
620db045 175
176=back
177
178=head1 BUGS
179
d4048ef3 180See L<Moose/BUGS> for details on reporting bugs.
620db045 181
620db045 182=cut