build variants in eval 'BEGIN { }' to allow namespace::clean to work seamlessly cleanable
Graham Knop [Mon, 20 Jan 2014 12:58:52 +0000 (07:58 -0500)]
lib/Package/Variant.pm
t/40-namespace-clean.t [new file with mode: 0644]

index df1739c..688185b 100644 (file)
@@ -1,8 +1,7 @@
 package Package::Variant;
 
 use strictures 1;
-use Import::Into;
-use Module::Runtime qw(require_module);
+use Module::Runtime qw(require_module module_notional_filename);
 use Carp qw(croak);
 
 our $VERSION = '1.002000'; # 1.2.0
@@ -97,23 +96,28 @@ sub import {
 sub build_variant_of {
   my ($me, $variable, @args) = @_;
   my $variant_name = "${variable}::_Variant_".++$Variable{$variable}{anon};
-  foreach my $to_import (@{$Variable{$variable}{args}{importing}}) {
-    my ($pkg, $args) = @$to_import;
-    require_module $pkg;
-    eval q{ BEGIN { $pkg->import::into($variant_name, @{$args}) }; 1; }
-      or die $@;
+  my $build = "package $variant_name;\n";
+  my $importing = $Variable{$variable}{args}{importing};
+  foreach my $i (0 .. $#$importing) {
+    my $pkg = $importing->[$i][0];
+    $build .= "use $pkg \@{\$importing->[$i][1]};\n";
   }
   my $subs = $Variable{$variable}{subs};
-  local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs;
-  local $Variable{$variable}{install} = sub {
-    my $full_name = "${variant_name}::".shift;
+  my $builder = sub {
+    local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs;
+    local $Variable{$variable}{install} = sub {
+      my $full_name = "${variant_name}::".shift;
 
-    my $ref = $sub_namer->($full_name, @_);
-    
-    no strict 'refs';
-    *$full_name = $ref;
+      my $ref = $sub_namer->($full_name, @_);
+
+      no strict 'refs';
+      *$full_name = $ref;
+    };
+    $variable->make_variant($variant_name, @args);
   };
-  $variable->make_variant($variant_name, @args);
+  $build .= "BEGIN { \$builder->() }\n1;\n";
+  eval $build or die $@;
+  $INC{module_notional_filename($variant_name)} = '(built by Package::Variant)';
   return $variant_name;
 }
 
diff --git a/t/40-namespace-clean.t b/t/40-namespace-clean.t
new file mode 100644 (file)
index 0000000..23ded83
--- /dev/null
@@ -0,0 +1,21 @@
+use strictures 1;
+use Test::More eval { require namespace::clean } ? ()
+  : (skip_all => 'namespace::clean needed for test');
+{
+  package CleanVariant;
+  use Package::Variant
+    importing => [
+      'Carp' => ['croak'],
+      'namespace::clean',
+    ],
+  ;
+
+  sub make_variant {
+    my ($class, $target_package, %arguments) = @_;
+    my $croak = $target_package->can('croak');
+    ::is $croak, \&Carp::croak, 'sub exists while building';
+  }
+}
+my $variant = CleanVariant->build_variant;
+is $variant->can('croak'), undef, 'sub cleaned after building';
+done_testing;