proper support for an Optional keyword
John Napiorkowski [Tue, 9 Sep 2008 22:14:09 +0000 (22:14 +0000)]
lib/MooseX/Types/Structured.pm
t/02-constraints.t

index 300a73c..e221391 100644 (file)
@@ -7,7 +7,7 @@ use MooseX::Meta::TypeConstraint::Structured::Named;
 #use MooseX::Types::Moose qw();
 #use MooseX::Types -declare => [qw( Dict Tuple Optional )];
   use Sub::Exporter
-    -setup => { exports => [ qw(Dict Tuple) ] };
+    -setup => { exports => [ qw(Dict Tuple Optional) ] };
        
 our $VERSION = '0.01';
 our $AUTHORITY = 'cpan:JJNAPIORK';
@@ -113,8 +113,12 @@ This class defines the following types and subtypes.
 
 =cut
 
-sub Tuple {
-       my ($args, $optional) = @_;
+sub Optional($) {
+    return bless {args=>shift}, 'MooseX::Types::Optional';
+}
+
+sub Tuple($) {
+       my ($args, $optional) = _normalize_args(@_);
        my @args = @$args;
        my @optional = ref $optional eq 'ARRAY' ? @$optional : ();
 
@@ -131,8 +135,8 @@ sub Tuple {
        );
 }
 
-sub Dict {
-       my ($args, $optional) = @_;
+sub Dict($) {
+       my ($args, $optional) = _normalize_args(@_);
        my %args = @$args;
        my %optional = ref $optional eq 'ARRAY' ? @$optional : ();
        
@@ -149,6 +153,21 @@ sub Dict {
        );
 }
 
+sub _normalize_args {
+    my $args = shift @_;
+    confess "Structured Type Constraints can only accept an ArrayRef as arguments"
+     unless ref $args eq 'ARRAY';
+     
+    my @args = @$args;
+    my $last = pop @args;
+    
+    if(blessed $last && $last->isa('MooseX::Types::Optional')) {
+        return ([@args], $last->{args});
+    } else {
+        return ([@args, $last]);
+    }
+    
+}
 sub _normalize_type_constraint {
        my $tc = shift @_;
        
index ba8cf30..270b68c 100644 (file)
@@ -9,7 +9,7 @@ BEGIN {
     package Test::MooseX::Meta::TypeConstraint::Structured;
 
     use Moose;
-    use MooseX::Types::Structured qw(Tuple Dict);
+    use MooseX::Types::Structured qw(Tuple Dict Optional);
        use Moose::Util::TypeConstraints;
 
     subtype 'MyString',
@@ -22,8 +22,8 @@ BEGIN {
        has 'tuple_with_param' => (is=>'rw', isa=>Tuple['Int', 'Str', 'ArrayRef[Int]']);
        has 'tuple_with_maybe' => (is=>'rw', isa=>Tuple['Int', 'Str', 'Maybe[Int]']);
        has 'dict_with_tuple' => (is=>'rw', isa=>Dict[key1=>'Str', key2=>Tuple['Int','Str']]);
-    has 'optional_tuple' => (is=>'rw', isa=>Tuple['Int', 'Int'],['Int'] );
-    has 'optional_dict' => (is=>'rw', isa=>Dict[key1=>'Int'],[key2=>'Int'] );
+    has 'optional_tuple' => (is=>'rw', isa=>Tuple['Int', 'Int', Optional['Int']] );
+    has 'optional_dict' => (is=>'rw', isa=>Dict[key1=>'Int', Optional[key2=>'Int']] );
     
     has 'crazy' => (
         is=>'rw',
@@ -35,19 +35,13 @@ BEGIN {
                 'MyString',
                 ## The third required element is a Dict type constraint, which
                 ## itself has two required keys and a third optional key.
-                Dict
-                                       [name=>'Str',age=>'Int'],
-                                       [visits=>'Int']
-            ],
-            ## Second ArrayRef Arg defines the optional constraints for the top
-            ## level Tuple.
-            [
-                'Int',
-                ## This Tuple has one required type constraint and two optional.
-                Tuple
-                                       ['Int'],
-                                       ['Int','HashRef'],
-            ],        
+                Dict[name=>'Str',age=>'Int', Optional[visits=>'Int']],
+                Optional[
+                    'Int',
+                    ## This Tuple has one required type constraint and two optional.
+                    Tuple['Int', Optional['Int','HashRef']],                    
+                ],
+            ],      
     );
 }