1 package Parse::Method::Signatures::TypeConstraint;
3 use Carp qw/croak carp/;
5 use MooseX::Types::Util qw/has_available_type_export/;
6 use MooseX::Types::Moose qw/Str HashRef CodeRef ClassName/;
7 use Parse::Method::Signatures::Types qw/TypeConstraint/;
9 use namespace::clean -except => 'meta';
13 isa => 'PPI::Element',
16 'to_string' => 'content'
22 isa => TypeConstraint,
24 builder => '_build_tc',
27 has from_namespace => (
30 predicate => 'has_from_namespace'
36 default => sub { \&find_registered_constraint },
39 sub find_registered_constraint {
40 my ($self, $name) = @_;
43 if ($self->has_from_namespace) {
44 my $pkg = $self->from_namespace;
46 if ($type = has_available_type_export($pkg, $name)) {
47 croak "The type '$name' was found in $pkg " .
48 "but it hasn't yet been defined. Perhaps you need to move the " .
49 "definition into a type library or a BEGIN block.\n"
50 if $type && $type->isa('MooseX::Types::UndefinedType');
53 my $meta = Class::MOP::class_of($pkg) || Class::MOP::Class->initialize($pkg);
54 my $func = $meta->get_package_symbol('&' . $name);
55 my $proto = prototype $func if $func;
58 if $func && defined $proto && !length $proto;
62 my $registry = Moose::Util::TypeConstraints->get_type_constraint_registry;
63 return $type || $registry->find_type_constraint($name) || $name;
69 my $tc = $self->_walk_data($self->ppi);
71 # This makes the error appear from the right place
72 local $Carp::Internal{'Class::MOP::Method::Generated'} = 1
73 unless exists $Carp::Internal{'Class::MOP::Method::Generated'};
75 croak "'@{[$self->ppi]}' could not be parsed to a type constraint - maybe you need to "
76 . "pre-declare the type with class_type"
82 my ($self, $data) = @_;
84 my $res = $self->_union_node($data)
85 || $self->_params_node($data)
86 || $self->_str_node($data)
87 || $self->_leaf($data)
88 or confess 'failed to visit tc';
93 my ($self, $data) = @_;
95 sub { $self->_invoke_callback($data->content) };
99 my ($self, $data) = @_;
100 return unless $data->isa('PPI::Statement::Expression::TCUnion');
102 my @types = map { $self->_walk_data($_) } $data->children;
104 scalar @types == 1 ? @types
105 : Moose::Meta::TypeConstraint::Union->new(type_constraints => \@types)
110 my ($self, $data) = @_;
111 return unless $data->isa('PPI::Statement::Expression::TCParams');
113 my @params = map { $self->_walk_data($_) } @{$data->params};
114 my $type = $self->_invoke_callback($data->type);
115 sub { $type->parameterize(@params) }
120 my ($self, $data) = @_;
121 return unless $data->isa('PPI::Token::StringifiedWord')
122 || $data->isa('PPI::Token::Number')
123 || $data->isa('PPI::Token::Quote');
126 $data->isa('PPI::Token::Number')
132 sub _invoke_callback {
134 $self->tc_callback->($self, @_);
137 __PACKAGE__->meta->make_immutable;
145 Parse::Method::Signatures::TypeConstraint - turn parsed TC data into Moose TC object
149 Class used to turn PPI elements into L<Moose::Meta::TypeConstraint> objects.
161 The L<Moose::Meta::TypeConstraint> object for this type constraint, built when
162 requested. L</tc_callback> will be called for each individual component type in
171 B<Default:> L</find_registered_constraint>
175 Callback used to turn type names into type objects. See
176 L<Parse::Method::Signatures/type_constraint_callback> for more details and an
179 =head2 from_namespace
187 If provided, then the default C<tc_callback> will search for L<MooseX::Types>
192 =head2 find_registered_constraint
194 Will search for an imported L<MooseX::Types> in L</from_namespace> (if
195 provided). Failing that it will ask the L<Moose::Meta::TypeConstraint::Registry>
196 for a type with the given name.
198 If all else fails, it will simple return the type as a string, so that Moose's
199 auto-vivification of classnames to type will work.
203 String representation of the type constraint, approximately as parsed.
207 L<Parse::Method::Signatures>, L<MooseX::Types>, L<MooseX::Types::Util>.
211 Florian Ragwitz <rafl@debian.org>.
213 Ash Berlin <ash@cpan.org>.
217 Licensed under the same terms as Perl itself.