use strict;
use warnings;
+use Carp 'confess';
use Sub::Name 'subname';
use Scalar::Util 'blessed';
our $VERSION = '0.02';
+use Moose::Meta::TypeConstraint;
+
sub import {
shift;
my $pkg = shift || caller();
return if $pkg eq ':no_export';
no strict 'refs';
- foreach my $export (qw(type subtype coerce as where to)) {
+ foreach my $export (qw(type subtype as where coerce from via)) {
*{"${pkg}::${export}"} = \&{"${export}"};
}
}
sub register_type_constraint {
my ($type_name, $type_constraint) = @_;
- $TYPES{$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 dump_type_constraints {
+ require Data::Dumper;
+ $Data::Dumper::Deparse = 1;
+ Data::Dumper::Dumper(\%TYPES);
}
sub export_type_contstraints_as_functions {
my $pkg = caller();
no strict 'refs';
foreach my $constraint (keys %TYPES) {
- *{"${pkg}::${constraint}"} = $TYPES{$constraint};
+ *{"${pkg}::${constraint}"} = $TYPES{$constraint}->constraint_code;
}
}
-}
-{
- my %COERCIONS;
sub find_type_coercion {
my $type_name = shift;
- $COERCIONS{$type_name};
+ $TYPES{$type_name}->coercion_code;
}
sub register_type_coercion {
my ($type_name, $type_coercion) = @_;
- $COERCIONS{$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);
}
}
my ($name, $check) = @_;
my $full_name = caller() . "::${name}";
register_type_constraint($name => subname $full_name => sub {
- return find_type_constraint($name) unless defined $_[0];
local $_ = $_[0];
return undef unless $check->($_[0]);
$_[0];
my ($name, $parent, $check) = @_;
if (defined $check) {
my $full_name = caller() . "::${name}";
- $parent = find_type_constraint($parent)
+ $parent = find_type_constraint($parent)->constraint_code
unless $parent && ref($parent) eq 'CODE';
- register_type_constraint($name => subname $full_name => sub {
- return find_type_constraint($name) unless defined $_[0];
+ 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)
+ $parent = find_type_constraint($parent)->constraint_code
unless $parent && ref($parent) eq 'CODE';
return subname '__anon_subtype__' => sub {
local $_ = $_[0];
}
}
-sub coerce {
- my ($type_name, %coercion_map) = @_;
+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)->constraint_code;
+ (defined $constraint)
+ || confess "Could not find the type constraint ($constraint_name)";
+ push @coercions => [ $constraint, $action ];
+ }
register_type_coercion($type_name, sub {
- %coercion_map
+ my $thing = shift;
+ foreach my $coercion (@coercions) {
+ my ($constraint, $converter) = @$coercion;
+ if (defined $constraint->($thing)) {
+ local $_ = $thing;
+ return $converter->($thing);
+ }
+ }
+ return $thing;
});
}
sub as ($) { $_[0] }
+sub from ($) { $_[0] }
sub where (&) { $_[0] }
-sub to (&) { $_[0] }
+sub via (&) { $_[0] }
# define some basic types
subtype NaturalLessThanTen
=> as Natural
=> where { $_ < 10 };
+
+ coerce Num
+ => from Str
+ => via { 0+$_ };
=head1 DESCRIPTION
This is B<NOT> a type system for Perl 5.
-The type and subtype constraints are basically functions which will
-validate their first argument. If called with no arguments, they will
-return themselves (this is syntactic sugar for Moose attributes).
-
This module also provides a simple hierarchy for Perl 5 types, this
could probably use some work, but it works for me at the moment.
=item B<export_type_contstraints_as_functions>
+=item B<dump_type_constraints>
+
=back
=head2 Type Constraint Constructors
=item B<coerce>
-=item B<to>
+=item B<from>
+
+=item B<via>
=back