Make sure that inlining union preserves the inline env
Dave Rolsky [Thu, 21 Apr 2011 20:51:36 +0000 (15:51 -0500)]
Make sure that an enum's inline env works when unioned with another enum (each env has a unique var)

lib/Moose/Meta/TypeConstraint.pm
lib/Moose/Meta/TypeConstraint/Enum.pm
lib/Moose/Meta/TypeConstraint/Union.pm
t/type_constraints/util_std_type_constraints.t

index 95e89de..d500356 100644 (file)
@@ -52,7 +52,7 @@ __PACKAGE__->meta->add_attribute('inlined' => (
 
 __PACKAGE__->meta->add_attribute('inline_environment' => (
     init_arg => 'inline_environment',
-    accessor => 'inline_environment',
+    accessor => '_inline_environment',
     default  => sub { {} },
 ));
 
@@ -160,6 +160,16 @@ sub _inline_check {
     return $self->inlined->( $self, @_ );
 }
 
+sub inline_environment {
+    my $self = shift;
+
+    if ( $self->has_parent && $self->constraint == $null_constraint ) {
+        return $self->parent->inline_environment;
+    }
+
+    return $self->_inline_environment;
+}
+
 sub assert_valid {
     my ($self, $value) = @_;
 
index 2a7a5ad..4dfc8ce 100644 (file)
@@ -13,15 +13,22 @@ __PACKAGE__->meta->add_attribute('values' => (
     accessor => 'values',
 ));
 
+__PACKAGE__->meta->add_attribute('_inline_var_name' => (
+    accessor => '_inline_var_name',
+));
+
 my $inliner = sub {
     my $self = shift;
     my $val  = shift;
 
     return 'defined(' . $val . ') '
              . '&& !ref(' . $val . ') '
-             . '&& $enums{' . $val . '}';
+             . '&& $' . $self->_inline_var_name . '{' . $val . '}';
 };
 
+# a quadrillion enums ought to be enough for any app
+my $var_suffix = '000000000000000000';
+
 sub new {
     my ( $class, %args ) = @_;
 
@@ -46,7 +53,10 @@ sub new {
 
     my %values = map { $_ => 1 } @{ $args{values} };
     $args{constraint} = sub { $values{ $_[0] } };
-    $args{inline_environment} = { '%enums' => \%values };
+
+    my $var_name = 'enums' . $var_suffix++;;
+    $args{_inline_var_name} = $var_name;
+    $args{inline_environment} = { '%' . $var_name => \%values };
 
     my $self = $class->_new(\%args);
 
index feb4697..ae0ea12 100644 (file)
@@ -86,6 +86,13 @@ sub _inline_check {
         @{ $self->type_constraints };
 };
 
+sub inline_environment {
+    my $self = shift;
+
+    return { map { %{ $_->inline_environment } }
+            @{ $self->type_constraints } };
+}
+
 sub equals {
     my ( $self, $type_or_name ) = @_;
 
index 181d647..0ff5b20 100644 (file)
@@ -949,6 +949,46 @@ for my $name ( sort keys %tests ) {
 }
 
 {
+    enum 'Enum1' => 'a', 'b';
+    enum 'Enum2' => 'x', 'y';
+
+    subtype 'EnumUnion', as 'Enum1 | Enum2';
+
+    test_constraint(
+        'EnumUnion', {
+            accept => [qw( a b x y )],
+            reject => [
+                $ZERO,
+                $ONE,
+                $INT,
+                $NEG_INT,
+                $NUM,
+                $NEG_NUM,
+                $EMPTY_STRING,
+                $STRING,
+                $NUM_IN_STRING,
+                $INT_WITH_NL1,
+                $INT_WITH_NL2,
+                $SCALAR_REF,
+                $SCALAR_REF_REF,
+                $ARRAY_REF,
+                $HASH_REF,
+                $CODE_REF,
+                $GLOB,
+                $GLOB_REF,
+                $FH,
+                $FH_OBJECT,
+                $REGEX,
+                $REGEX_OBJ,
+                $FAKE_REGEX,
+                $OBJECT,
+                $UNDEF,
+            ],
+        }
+    );
+}
+
+{
     package DoesRole;
 
     use Moose;