I poked and prodded it in my usual semi-understanding way and came up with this diff...
######################################
--- /home/alex/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/Test/Kit.pm 2013-10-16 09:22:04.000000000 +0100
+++ 01-test-aggregate/lib/Test/Kit.pm 2013-10-17 14:23:29.000000000 +0100
@@ -103,7 +103,7 @@
and excluding. To do this, add a hashref after the module name with keys
'exclude', 'rename', or both.
- use Test::Most
+ use Test::Most
'Test::Something' => {
# or a scalar for just one
exclude => [qw/ list of excluded functions/],
@@ -122,7 +122,7 @@
sub import {
my $class = shift;
- my $callpack = caller(1);
+ my $callpack = $class->_get_callpack();
my $basic_functions = namespace::clean->get_functions($class);
@@ -153,11 +153,44 @@
return 1;
}
+sub _get_callpack {
+ my $class = shift;
+
+ my $callpack;
+
+ # so, as far as I can tell, on Perl 5.14 and 5.16 at least, we have the
+ # following callstack...
+ #
+ # 1. Test::Kit::import,
+ # 2. MyTest::BEGIN
+ # 3. (eval)
+ # 4. (eval)
+ # 5. main::BEGIN
+ # 6. (eval)
+ #
+ # ... and we want to get the package name "MyTest" out of there.
+ # So, let's look for the first occurrence of BEGIN or something!
+
+ my @begins = grep { m/::BEGIN$/ }
+ map { (caller($_))[3] }
+ 1 .. 10;
+
+ if ($begins[0] && $begins[0] =~ m/^ (.+) ::BEGIN $/msx) {
+ $callpack = $1;
+ }
+ else {
+ die "Unable to determine callpack for some reason...";
+ }
+
+ return $callpack;
+}
+
sub _setup_import {
my ( $class, $features ) = @_;
- my $callpack = caller(1); # this is the composed test package
+ my $callpack = $class->_get_callpack();
my $import = "$callpack\::import";
my $isa = "$callpack\::ISA";
+ my $export = "$callpack\::EXPORT";
no strict 'refs';
if ( defined &$import ) {
Carp::croak("Class $callpack must not define an &import method");
@@ -166,9 +199,20 @@
unshift @$isa => 'Test::Kit::Features';
*$import = sub {
my ( $class, @args ) = @_;
+
@args = $class->BUILD(@args) if $class->can('BUILD');
@args = $class->_setup_features( $features, @args );
@_ = ( $class, @args );
+
+ no strict 'refs';
+ @$export = keys %{ namespace::clean->get_functions($class) };
+
+ # HACK!
+ @$export = grep { $_ ne 'import' } @$export;
+ @$export = grep { $_ ne 'BEGIN' } @$export;
+ push @$export, '$TODO';
+ # END HACK!
+
goto &Test::Builder::Module::import;
};
}
######################################
There's really two changes here:
1. We call _get_callpack() instead of caller(1), which correctly gets the name of the class that is using Test::Kit in all cases.
2. We set @EXPORT on that class before goto'ing to Test::Builder::Module::import so that Test::Builder::Module::import() (which is really just Exporter::import()) actually exports some functions.
Not sure if this is the expected behaviour or the nicest/cleanest/most-fitting-in implementation of those two fixes... but as far as I can tell it makes these cases work!
Unfortunately it doesn't pass all the tests in the current test suite... basic.t is failing to compile (or rather, failing during BEGIN) and exceptions.t is catching a differently named exception now.
Will look into those at some point, unless you want to jump in :-)
--- /home/alex/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/Test/Kit.pm 2013-10-16 09:22:04.000000000 +0100
+++ 01-test-aggregate/lib/Test/Kit.pm 2013-10-17 14:23:29.000000000 +0100
@@ -103,7 +103,7 @@
and excluding. To do this, add a hashref after the module name with keys
'exclude', 'rename', or both.
- use Test::Most
+ use Test::Most
'Test::Something' => {
# or a scalar for just one
exclude => [qw/ list of excluded functions/],
@@ -122,7 +122,7 @@
sub import {
my $class = shift;
- my $callpack = caller(1);
+ my $callpack = $class->_get_callpack();
my $basic_functions = namespace::clean->get_functions($class);
@@ -153,11 +153,44 @@
return 1;
}
+sub _get_callpack {
+ my $class = shift;
+
+ my $callpack;
+
+ # so, as far as I can tell, on Perl 5.14 and 5.16 at least, we have the
+ # following callstack...
+ #
+ # 1. Test::Kit::import,
+ # 2. MyTest::BEGIN
+ # 3. (eval)
+ # 4. (eval)
+ # 5. main::BEGIN
+ # 6. (eval)
+ #
+ # ... and we want to get the package name "MyTest" out of there.
+ # So, let's look for the first occurrence of BEGIN or something!
+
+ my @begins = grep { m/::BEGIN$/ }
+ map { (caller($_))[3] }
+ 1 .. 10;
+
+ if ($begins[0] && $begins[0] =~ m/^ (.+) ::BEGIN $/msx) {
+ $callpack = $1;
+ }
+ else {
+ die "Unable to determine callpack for some reason...";
+ }
+
+ return $callpack;
+}
+
sub _setup_import {
my ( $class, $features ) = @_;
- my $callpack = caller(1); # this is the composed test package
+ my $callpack = $class->_get_callpack();
my $import = "$callpack\::import";
my $isa = "$callpack\::ISA";
+ my $export = "$callpack\::EXPORT";
no strict 'refs';
if ( defined &$import ) {
Carp::croak("Class $callpack must not define an &import method");
@@ -166,9 +199,20 @@
unshift @$isa => 'Test::Kit::Features';
*$import = sub {
my ( $class, @args ) = @_;
+
@args = $class->BUILD(@args) if $class->can('BUILD');
@args = $class->_setup_features( $features, @args );
@_ = ( $class, @args );
+
+ no strict 'refs';
+ @$export = keys %{ namespace::clean->get_functions($class) };
+
+ # HACK!
+ @$export = grep { $_ ne 'import' } @$export;
+ @$export = grep { $_ ne 'BEGIN' } @$export;
+ push @$export, '$TODO';
+ # END HACK!
+
goto &Test::Builder::Module::import;
};
}