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