add a map type
Ricardo Signes [Mon, 25 Jan 2010 23:15:52 +0000 (18:15 -0500)]
lib/MooseX/Types/Structured.pm
t/04-map.t [new file with mode: 0644]

index 998bee9..10019af 100644 (file)
@@ -5,8 +5,8 @@ use 5.008;
 use Moose::Util::TypeConstraints;
 use MooseX::Meta::TypeConstraint::Structured;
 use MooseX::Types::Structured::OverflowHandler;
-use MooseX::Types -declare => [qw(Dict Tuple Optional)];
-use Sub::Exporter -setup => { exports => [ qw(Dict Tuple Optional slurpy) ] };
+use MooseX::Types -declare => [qw(Dict Map Tuple Optional)];
+use Sub::Exporter -setup => [ qw(Dict Map Tuple Optional slurpy) ];
 use Devel::PartialDump;
 use Scalar::Util qw(blessed);
 
@@ -805,6 +805,46 @@ Moose::Util::TypeConstraints::get_type_constraint_registry->add_type_constraint(
        )
 );
 
+Moose::Util::TypeConstraints::get_type_constraint_registry->add_type_constraint(
+  MooseX::Meta::TypeConstraint::Structured->new(
+    name => "MooseX::Types::Structured::Map",
+    parent => find_type_constraint('HashRef'),
+    constraint_generator=> sub { 
+      ## Get the constraints and values to check
+      my ($type_constraints, $values) = @_;
+      my @constraints = defined $type_constraints ? @$type_constraints : ();
+            
+      Carp::confess( "too many args for Map type" ) if @constraints > 2;
+
+      my ($key_type, $value_type) = @constraints == 2 ? @constraints
+                                  : @constraints == 1 ? (undef, @constraints)
+                                  :                     ();
+
+      my %values = defined $values ? %$values: ();
+      ## Perform the checking
+      if ($value_type) {
+        for my $value (values %$values) {
+          unless ($value_type->check($value)) {
+            $_[2]->{message} = $value_type->get_message($value) if ref $_[2];
+            return;
+          }
+        }
+      }
+
+      if ($key_type) {
+        for my $key (keys %$values) {
+          unless ($key_type->check($key)) {
+            $_[2]->{message} = $key_type->get_message($key) if ref $_[2];
+            return;
+          }
+        }
+      }
+
+      return 1;
+    },
+  )
+);
+
 OPTIONAL: {
     my $Optional = Moose::Meta::TypeConstraint::Parameterizable->new(
         name => 'MooseX::Types::Structured::Optional',
diff --git a/t/04-map.t b/t/04-map.t
new file mode 100644 (file)
index 0000000..b976b1a
--- /dev/null
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+use Test::More;
+
+use MooseX::Types::Moose qw(Int Num);
+use MooseX::Types::Structured qw(Map);
+use Try::Tiny;
+
+my $type = Map[ Int, Num ];
+
+ok($type->assert_valid({ 10 => 10.5 }), "simple Int -> Num mapping");
+
+eval { $type->assert_valid({ 10.5 => 10.5 }) };
+like($@, qr{value 10\.5}, "non-Int causes rejection on key");
+
+eval { $type->assert_valid({ 10 => "ten and a half" }) };
+like("$@", qr{value ten and a half}, "non-Num value causes rejection on value");
+
+ok($type->assert_valid({ }), "empty hashref is a valid mapping of any sort");
+
+done_testing;
+