package ## Hide from PAUSE
 MooseX::Meta::TypeCoercion::Parameterizable;

use Moose;
extends 'Moose::Meta::TypeCoercion';

=head1 NAME

MooseX::Meta::TypeCoercion::Parameterizable - Coerce Parameterizable type constraints.

=head1 DESCRIPTION

This class is not intended for public consumption.  Please don't subclass it
or rely on it.  Chances are high stuff here is going to change a lot.

=head1 METHODS

This class defines the following methods.

=head add_type_coercions

method modification to throw exception should we try to add a coercion on a
parameterizable type that is already defined by a constraining value.  We do this
since defined parameterizable type constraints inherit their coercion from the parent
constraint.  It makes no sense to even be using parameterizable types if you know the
constraining value beforehand!

=cut

around 'add_type_coercions' => sub {
    my ($add_type_coercions, $self, @args) = @_;
    if($self->type_constraint->has_constraining_value) {
        Moose->throw_error("Cannot add type coercions to a parameterizable type constraint that's been defined.");
    } else {
        return $self->$add_type_coercions(@args);
    }
};


## These two are here until I can merge change upstream to Moose.  These are two
## very minor changes we can probably just put into Moose without breaking stuff
sub coerce {
    my $self = shift @_;
    my $coderef = $self->_compiled_type_coercion;
    return $coderef->(@_);
}

sub compile_type_coercion {
    my $self = shift;
    my @coercion_map = @{$self->type_coercion_map};
    my @coercions;
    while (@coercion_map) {
        my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
        my $type_constraint = ref $constraint_name ? $constraint_name : Moose::Util::TypeConstraints::find_or_parse_type_constraint($constraint_name);

        unless ( defined $type_constraint ) {
            require Moose;
            Moose->throw_error("Could not find the type constraint ($constraint_name) to coerce from");
        }

        push @coercions => [
            $type_constraint->_compiled_type_constraint,
            $action
        ];
    }
    $self->_compiled_type_coercion(sub {
        my $thing = shift;
        foreach my $coercion (@coercions) {
            my ($constraint, $converter) = @$coercion;
            if ($constraint->($thing)) {
                local $_ = $thing;
                return $converter->($thing, @_);
            }
        }
        return $thing;
    });
}

=head1 SEE ALSO

The following modules or resources may be of interest.

L<Moose>, L<Moose::Meta::TypeCoercion>

=head1 AUTHOR

John Napiorkowski, C<< <jjnapiork@cpan.org> >>

=head1 COPYRIGHT & LICENSE

This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

__PACKAGE__->meta->make_immutable(inline_constructor => 0);
