Test case specifically, test script cleanup
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
index da0da30..95bbfd7 100644 (file)
@@ -9,7 +9,7 @@ use Scalar::Util 'blessed', 'reftype';
 use B            'svref_2object';
 use Sub::Exporter;
 
-our $VERSION   = '0.14';
+our $VERSION   = '0.15';
 our $AUTHORITY = 'cpan:STEVAN';
 
 ## --------------------------------------------------------
@@ -20,10 +20,10 @@ our $AUTHORITY = 'cpan:STEVAN';
 # compiled.
 
 # creation and location
-sub find_type_constraint             ($);
-sub find_or_create_type_constraint   ($;$);
-sub create_type_constraint_union     (@);
-sub create_container_type_constraint ($);
+sub find_type_constraint                 ($);
+sub find_or_create_type_constraint       ($;$);
+sub create_type_constraint_union         (@);
+sub create_parameterized_type_constraint ($);
 
 # dah sugah!
 sub type        ($$;$$);
@@ -45,7 +45,7 @@ sub _install_type_coercions ($$);
 
 use Moose::Meta::TypeConstraint;
 use Moose::Meta::TypeConstraint::Union;
-use Moose::Meta::TypeConstraint::Container;
+use Moose::Meta::TypeConstraint::Parameterized;
 use Moose::Meta::TypeCoercion;
 use Moose::Meta::TypeCoercion::Union;
 use Moose::Meta::TypeConstraint::Registry;
@@ -102,8 +102,8 @@ sub export_type_constraints_as_functions {
 sub create_type_constraint_union (@) {
     my @type_constraint_names;
     
-    if (scalar @_ == 1 && $_[0] =~ /\|/) {
-        @type_constraint_names = (split /\s*\|\s*/ => $_[0]);
+    if (scalar @_ == 1 && _detect_type_constraint_union($_[0])) {
+        @type_constraint_names = _parse_type_constraint_union($_[0]);
     }
     else {
         @type_constraint_names = @_;
@@ -125,24 +125,26 @@ sub create_type_constraint_union (@) {
     );    
 }
 
-sub create_container_type_constraint ($) {
+sub create_parameterized_type_constraint ($) {
     my $type_constraint_name = shift;
     
-    my ($base_type, $container_type) = ($type_constraint_name =~ /^(.*)\[(.*)\]$/);
+    my ($base_type, $type_parameter) = _parse_parameterized_type_constraint($type_constraint_name);
     
-    (defined $base_type && defined $container_type)
+    (defined $base_type && defined $type_parameter)
         || confess "Could not parse type name ($type_constraint_name) correctly";
     
     ($REGISTRY->has_type_constraint($base_type))
         || confess "Could not locate the base type ($base_type)";
-        
-    ($REGISTRY->has_type_constraint($container_type))
-        || confess "Could not locate the container type ($container_type)";
     
-    return Moose::Meta::TypeConstraint::Container->new(
+    return Moose::Meta::TypeConstraint::Parameterized->new(
         name           => $type_constraint_name,
         parent         => $REGISTRY->get_type_constraint($base_type),
-        container_type => $REGISTRY->get_type_constraint($container_type),
+        type_parameter => find_or_create_type_constraint(
+            $type_parameter => {
+                parent     => $REGISTRY->get_type_constraint('Object'),
+                constraint => sub { $_[0]->isa($type_parameter) }
+            }
+        ),
     );    
 }
 
@@ -154,11 +156,11 @@ sub find_or_create_type_constraint ($;$) {
     
     my $constraint;
     
-    if ($type_constraint_name =~ /\|/) {
+    if (_detect_type_constraint_union($type_constraint_name)) {
         $constraint = create_type_constraint_union($type_constraint_name);
     }
-    elsif ($type_constraint_name =~ /^.*?\[.*?\]$/) {
-        $constraint = create_container_type_constraint($type_constraint_name);       
+    elsif (_detect_parameterized_type_constraint($type_constraint_name)) {
+        $constraint = create_parameterized_type_constraint($type_constraint_name);       
     }
     else {
         # NOTE:
@@ -222,11 +224,11 @@ sub enum ($;@) {
     my ($type_name, @values) = @_;
     (scalar @values >= 2)
         || confess "You must have at least two values to enumerate through";
-    my $regexp = join '|' => @values;
+    my %valid = map { $_ => 1 } @values;
        _create_type_constraint(
            $type_name,
            'Str',
-           sub { qr/^$regexp$/i }
+           sub { $valid{$_} }
        );    
 }
 
@@ -287,6 +289,60 @@ sub _install_type_coercions ($$) {
 }
 
 ## --------------------------------------------------------
+## type notation parsing ...
+## --------------------------------------------------------
+
+{
+    # All I have to say is mugwump++ cause I know 
+    # do not even have enough regexp-fu to be able 
+    # to have written this (I can only barely 
+    # understand it as it is)
+    # - SL 
+    
+    use re "eval";
+
+    my $valid_chars = qr{[\w:]};
+    my $type_atom   = qr{ $valid_chars+ };
+
+    my $type                = qr{  $valid_chars+  (?: \[  (??{$any})  \] )? }x;
+    my $type_capture_parts  = qr{ ($valid_chars+) (?: \[ ((??{$any})) \] )? }x;
+    my $type_with_parameter = qr{  $valid_chars+      \[  (??{$any})  \]    }x;
+
+    my $op_union = qr{ \s* \| \s* }x;
+    my $union    = qr{ $type (?: $op_union $type )+ }x;
+
+    our $any = qr{ $type | $union }x;
+
+    sub _parse_parameterized_type_constraint {
+       $_[0] =~ m{ $type_capture_parts }x;
+       return ($1, $2);
+    }
+
+    sub _detect_parameterized_type_constraint {
+       $_[0] =~ m{ ^ $type_with_parameter $ }x;
+    }
+
+    sub _parse_type_constraint_union {
+       my $given = shift;
+       my @rv;
+       while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) {
+               push @rv => $1;
+       }
+       (pos($given) eq length($given))
+           || confess "'$given' didn't parse (parse-pos=" 
+                    . pos($given) 
+                    . " and str-length="
+                    . length($given)
+                    . ")";
+       @rv;
+    }
+
+    sub _detect_type_constraint_union {
+       $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x;
+    }
+}
+
+## --------------------------------------------------------
 # define some basic built-in types
 ## --------------------------------------------------------
 
@@ -517,14 +573,14 @@ test file.
 Given string with C<$pipe_seperated_types> or a list of C<@type_constraint_names>, 
 this will return a L<Moose::Meta::TypeConstraint::Union> instance.
 
-=item B<create_container_type_constraint ($type_name)>
+=item B<create_parameterized_type_constraint ($type_name)>
 
 Given a C<$type_name> in the form of:
 
   BaseType[ContainerType]
 
 this will extract the base type and container type and build an instance of 
-L<Moose::Meta::TypeConstraint::Container> for it.
+L<Moose::Meta::TypeConstraint::Parameterized> for it.
 
 =item B<find_or_create_type_constraint ($type_name, ?$options_for_anon_type)>
 
@@ -593,8 +649,8 @@ L<Moose::Meta::TypeConstraint>.
 
 This will create a basic subtype for a given set of strings. 
 The resulting constraint will be a subtype of C<Str> and 
-will match any of the items in C<@values>. See the L<SYNOPSIS> 
-for a simple example.
+will match any of the items in C<@values>. It is case sensitive.
+See the L<SYNOPSIS> for a simple example.
 
 B<NOTE:> This is not a true proper enum type, it is simple 
 a convient constraint builder.