use warnings;
use Carp 'confess';
-use Sub::Name 'subname';
use Scalar::Util 'blessed';
our $VERSION = '0.02';
use Moose::Meta::TypeConstraint;
+use Moose::Meta::TypeCoercion;
sub import {
shift;
my $pkg = shift || caller();
- return if $pkg eq ':no_export';
+ return if $pkg eq '-no-export';
no strict 'refs';
- foreach my $export (qw(type subtype as where coerce from via)) {
+ foreach my $export (qw(type subtype as where coerce from via find_type_constraint)) {
*{"${pkg}::${export}"} = \&{"${export}"};
}
}
{
my %TYPES;
- sub find_type_constraint {
- my $type_name = shift;
- $TYPES{$type_name}->constraint_code;
- }
-
- sub register_type_constraint {
- my ($type_name, $type_constraint) = @_;
- (not exists $TYPES{$type_name})
- || confess "The type constraint '$type_name' has already been registered";
- $TYPES{$type_name} = Moose::Meta::TypeConstraint->new(
- name => $type_name,
- constraint_code => $type_constraint
+ sub find_type_constraint { $TYPES{$_[0]} }
+
+ sub _create_type_constraint {
+ my ($name, $parent, $check) = @_;
+ (!exists $TYPES{$name})
+ || confess "The type constraint '$name' has already been created"
+ if defined $name;
+ $parent = $TYPES{$parent} if defined $parent;
+ my $constraint = Moose::Meta::TypeConstraint->new(
+ name => $name || '__ANON__',
+ parent => $parent,
+ constraint => $check,
);
+ $TYPES{$name} = $constraint if defined $name;
+ return $constraint;
}
-
- sub dump_type_constraints {
- require Data::Dumper;
- $Data::Dumper::Deparse = 1;
- Data::Dumper::Dumper(\%TYPES);
+
+ sub _install_type_coercions {
+ my ($type_name, $coercion_map) = @_;
+ my $type = $TYPES{$type_name};
+ (!$type->has_coercion)
+ || confess "The type coercion for '$type_name' has already been registered";
+ my $type_coercion = Moose::Meta::TypeCoercion->new(
+ type_coercion_map => $coercion_map,
+ type_constraint => $type
+ );
+ $type->coercion($type_coercion);
}
sub export_type_contstraints_as_functions {
my $pkg = caller();
no strict 'refs';
foreach my $constraint (keys %TYPES) {
- *{"${pkg}::${constraint}"} = $TYPES{$constraint}->constraint_code;
+ *{"${pkg}::${constraint}"} = $TYPES{$constraint}->_compiled_type_constraint;
}
- }
-
- sub find_type_coercion {
- my $type_name = shift;
- $TYPES{$type_name}->coercion_code;
- }
-
- sub register_type_coercion {
- my ($type_name, $type_coercion) = @_;
- my $type = $TYPES{$type_name};
- (!$type->has_coercion)
- || confess "The type coercion for '$type_name' has already been registered";
- $type->set_coercion_code($type_coercion);
- }
+ }
}
+# type constructors
sub type ($$) {
my ($name, $check) = @_;
- my $full_name = caller() . "::${name}";
- register_type_constraint($name => subname $full_name => sub {
- local $_ = $_[0];
- return undef unless $check->($_[0]);
- $_[0];
- });
+ _create_type_constraint($name, undef, $check);
}
sub subtype ($$;$) {
- my ($name, $parent, $check) = @_;
- if (defined $check) {
- my $full_name = caller() . "::${name}";
- $parent = find_type_constraint($parent)
- unless $parent && ref($parent) eq 'CODE';
- register_type_constraint($name => subname $full_name => sub {
- local $_ = $_[0];
- return undef unless defined $parent->($_[0]) && $check->($_[0]);
- $_[0];
- });
- }
- else {
- ($parent, $check) = ($name, $parent);
- $parent = find_type_constraint($parent)
- unless $parent && ref($parent) eq 'CODE';
- return subname '__anon_subtype__' => sub {
- local $_ = $_[0];
- return undef unless defined $parent->($_[0]) && $check->($_[0]);
- $_[0];
- };
- }
+ unshift @_ => undef if scalar @_ == 2;
+ _create_type_constraint(@_);
}
sub coerce ($@) {
- my ($type_name, @coercion_map) = @_;
- #use Data::Dumper;
- #warn Dumper \@coercion_map;
- my @coercions;
- while (@coercion_map) {
- my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
- my $constraint = find_type_constraint($constraint_name);
- (defined $constraint)
- || confess "Could not find the type constraint ($constraint_name)";
- push @coercions => [ $constraint, $action ];
- }
- register_type_coercion($type_name, sub {
- my $thing = shift;
- foreach my $coercion (@coercions) {
- my ($constraint, $converter) = @$coercion;
- if (defined $constraint->($thing)) {
- local $_ = $thing;
- return $converter->($thing);
- }
- }
- return $thing;
- });
+ my ($type_name, @coercion_map) = @_;
+ _install_type_coercions($type_name, \@coercion_map);
}
sub as ($) { $_[0] }
=item B<find_type_constraint ($type_name)>
-=item B<register_type_constraint ($type_name, $type_constraint)>
+=item B<_create_type_constraint ($type_name, $type_constraint)>
-=item B<find_type_coercion>
-
-=item B<register_type_coercion>
+=item B<_install_type_coercions>
=item B<export_type_contstraints_as_functions>
-=item B<dump_type_constraints>
-
=back
=head2 Type Constraint Constructors