diff options
-rw-r--r-- | Changes | 46 | ||||
-rw-r--r-- | MANIFEST | 16 | ||||
-rw-r--r-- | META.json | 48 | ||||
-rw-r--r-- | META.yml | 25 | ||||
-rw-r--r-- | Makefile.PL | 74 | ||||
-rw-r--r-- | README | 54 | ||||
-rw-r--r-- | lib/Sub/Exporter/Progressive.pm | 158 | ||||
-rw-r--r-- | maint/Makefile.PL.include | 7 | ||||
-rw-r--r-- | t/all.t | 22 | ||||
-rw-r--r-- | t/basic.t | 13 | ||||
-rw-r--r-- | t/default.t | 13 | ||||
-rw-r--r-- | t/lib/A/Junk.pm | 15 | ||||
-rw-r--r-- | t/lib/A/JunkAll.pm | 13 | ||||
-rw-r--r-- | t/sex.t | 18 | ||||
-rw-r--r-- | t/tags.t | 69 | ||||
-rw-r--r-- | t/version-check.t | 42 |
16 files changed, 633 insertions, 0 deletions
@@ -0,0 +1,46 @@ +0.001011 - 2013-10-28 + - Fix in global destruction (Graham Knop) + - Fix SYNOPSIS + - Fix duplicate word in DESCRIPTION (RT#86072) + +0.001010 - 2013-03-26 + - Fix module name in Makefile.PL (RT#83932) + - Work around Exporter.pm not installable on perl < 5.8.0 + +0.001009 - 2013-03-12 + - disallow version names in random parts of the import list for consistency + with Sub::Exporter (Toby Inkster) + - perl 5.6 support + - more metadata + +0.001008 - 2013-01-22 + - Fix prereqs + +0.001007 - 2013-01-21 + - Rewrite -tag to :tag for Exporter.pm + +0.001006 - 2012-08-27 + - Handle ':all' correctly + +0.001005 - 2012-08-25 + - Add support for tags + - Warn if defaults are not in exports + - Add explicit dependency on Test::More 0.89 + +0.001004 - 2012-08-09 + - fix skipping when Sub::Exporter isn't installed + +0.001003 2012-08-01 12:47:28 America/Chicago + - remove warning if there are no defaults + +0.001002 2012-07-31 08:59:43 America/Chicago + - Make Sub::Exporter an optional dep (which is kinda the whole point) + - warning about too complex usage of Sub::Exporter::Progressive is now + an exception + +0.001001 2012-07-29 19:58:40 America/Chicago + - Fix '-all' option for the default group + +0.001000 2012-07-29 16:44:01 America/Chicago + - Initial Release + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..322859c --- /dev/null +++ b/MANIFEST @@ -0,0 +1,16 @@ +Changes +lib/Sub/Exporter/Progressive.pm +maint/Makefile.PL.include +Makefile.PL +MANIFEST This list of files +t/all.t +t/basic.t +t/default.t +t/lib/A/Junk.pm +t/lib/A/JunkAll.pm +t/sex.t +t/tags.t +t/version-check.t +META.yml Module YAML meta-data (added by MakeMaker) +META.json Module JSON meta-data (added by MakeMaker) +README README file (added by Distar) diff --git a/META.json b/META.json new file mode 100644 index 0000000..1be9698 --- /dev/null +++ b/META.json @@ -0,0 +1,48 @@ +{ + "abstract" : "Only use Sub::Exporter if you need it", + "author" : [ + "frew - Arthur Axel Schmidt (cpan:FREW) <frioux+cpan@gmail.com>" + ], + "dynamic_config" : 0, + "generated_by" : "ExtUtils::MakeMaker version 6.8, CPAN::Meta::Converter version 2.132830", + "license" : [ + "perl_5" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : "2" + }, + "name" : "Sub-Exporter-Progressive", + "no_index" : { + "directory" : [ + "t", + "inc" + ] + }, + "prereqs" : { + "build" : { + "requires" : { + "Test::More" : "0.88" + } + }, + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + } + }, + "runtime" : { + "requires" : {} + } + }, + "release_status" : "stable", + "resources" : { + "bugtracker" : { + "web" : "http://rt.cpan.org/Public/Dist/Display.html?Name=Sub-Exporter-Progressive" + }, + "homepage" : "http://search.cpan.org/dist/Sub-Exporter-Progressive/", + "repository" : { + "url" : "git://git.shadowcat.co.uk/p5sagit/Sub-Exporter-Progressive.git" + } + }, + "version" : "0.001011" +} diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..db8d151 --- /dev/null +++ b/META.yml @@ -0,0 +1,25 @@ +--- +abstract: 'Only use Sub::Exporter if you need it' +author: + - 'frew - Arthur Axel Schmidt (cpan:FREW) <frioux+cpan@gmail.com>' +build_requires: + Test::More: 0.88 +configure_requires: + ExtUtils::MakeMaker: 0 +dynamic_config: 0 +generated_by: 'ExtUtils::MakeMaker version 6.8, CPAN::Meta::Converter version 2.132830' +license: perl +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Sub-Exporter-Progressive +no_index: + directory: + - t + - inc +requires: {} +resources: + bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Sub-Exporter-Progressive + homepage: http://search.cpan.org/dist/Sub-Exporter-Progressive/ + repository: git://git.shadowcat.co.uk/p5sagit/Sub-Exporter-Progressive.git +version: 0.001011 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..037f594 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,74 @@ +use strict; +use warnings; + +use 5.006; +use ExtUtils::MakeMaker; +(do 'maint/Makefile.PL.include' or die $@) unless -f 'META.yml'; + +my %BUILD_DEPS = ( + 'Test::More' => '0.88' +); + +my %RUN_DEPS = ( +); + +my %META_BITS = ( + resources => { + homepage => 'http://search.cpan.org/dist/Sub-Exporter-Progressive/', + repository => 'git://git.shadowcat.co.uk/p5sagit/Sub-Exporter-Progressive.git', + bugtracker => 'http://rt.cpan.org/Public/Dist/Display.html?Name=Sub-Exporter-Progressive', + }, + requires => \%RUN_DEPS, + dynamic_config => 0, +); + +my $mymeta_works = eval { ExtUtils::MakeMaker->VERSION('6.5707'); 1 }; +my $mymeta = $mymeta_works || eval { ExtUtils::MakeMaker->VERSION('6.5702'); 1 }; + +my %WriteMakefileArgs = ( + NAME => 'Sub::Exporter::Progressive', + VERSION_FROM => 'lib/Sub/Exporter/Progressive.pm', + ABSTRACT_FROM => 'lib/Sub/Exporter/Progressive.pm', + LICENSE => 'perl', + PREREQ_PM => { + %RUN_DEPS, + $mymeta_works ? () : (%BUILD_DEPS), + }, + + $mymeta_works + ? ( # BUILD_REQUIRES makes MYMETA right, requires stops META being wrong + 'BUILD_REQUIRES' => \%BUILD_DEPS, + 'META_ADD' => { + %META_BITS, + requires => \%RUN_DEPS, + }, + ) + : ( # META_ADD both to get META right - only Makefile written + 'META_ADD' => { + %META_BITS, + requires => \%RUN_DEPS, + build_requires => \%BUILD_DEPS, + }, + ) + , + + ($mymeta and !$mymeta_works) ? ( 'NO_MYMETA' => 1 ) : (), +); + +unless ( eval { ExtUtils::MakeMaker->VERSION('6.56') } ) { + my $br = delete $WriteMakefileArgs{BUILD_REQUIRES}; + my $pp = $WriteMakefileArgs{PREREQ_PM}; + for my $mod ( keys %$br ) { + if ( exists $pp->{$mod} ) { + $pp->{$mod} = $br->{$mod} if $br->{$mod} > $pp->{$mod}; + } + else { + $pp->{$mod} = $br->{$mod}; + } + } +} + +delete $WriteMakefileArgs{CONFIGURE_REQUIRES} + unless eval { ExtUtils::MakeMaker->VERSION('6.52') }; + +WriteMakefile(%WriteMakefileArgs); @@ -0,0 +1,54 @@ +NAME + Sub::Exporter::Progressive - Only use Sub::Exporter if you need it + +SYNOPSIS + package Syntax::Keyword::Gather; + + use Sub::Exporter::Progressive -setup => { + exports => [qw( break gather gathered take )], + groups => { + default => [qw( break gather gathered take )], + }, + }; + + # elsewhere + + # uses Exporter for speed + use Syntax::Keyword::Gather; + + # somewhere else + + # uses Sub::Exporter for features + use Syntax::Keyword::Gather 'gather', take => { -as => 'grab' }; + +DESCRIPTION + Sub::Exporter is an incredibly powerful module, but with that power + comes great responsibility, er- as well as some runtime penalties. This + module is a "Sub::Exporter" wrapper that will let your users just use + Exporter if all they are doing is picking exports, but use + "Sub::Exporter" if your users try to use "Sub::Exporter"'s more advanced + features, like renaming exports, if they try to use them. + + Note that this module will export @EXPORT, @EXPORT_OK and %EXPORT_TAGS + package variables for "Exporter" to work. Additionally, if your package + uses advanced "Sub::Exporter" features like currying, this module will + only ever use "Sub::Exporter", so you might as well use it directly. + +AUTHOR + frew - Arthur Axel Schmidt (cpan:FREW) <frioux+cpan@gmail.com> + +CONTRIBUTORS + ilmari - Dagfinn Ilmari Mannsåker (cpan:ILMARI) <ilmari@ilmari.org> + + mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk> + + leont - Leon Timmermans (cpan:LEONT) <leont@cpan.org> + +COPYRIGHT + Copyright (c) 2012 the Sub::Exporter::Progressive "AUTHOR" and + "CONTRIBUTORS" as listed above. + +LICENSE + This library is free software and may be distributed under the same + terms as perl itself. + diff --git a/lib/Sub/Exporter/Progressive.pm b/lib/Sub/Exporter/Progressive.pm new file mode 100644 index 0000000..0ee231a --- /dev/null +++ b/lib/Sub/Exporter/Progressive.pm @@ -0,0 +1,158 @@ +package Sub::Exporter::Progressive; + +use strict; +use warnings; + +our $VERSION = '0.001011'; + +use Carp (); +use List::Util (); + +sub import { + my ($self, @args) = @_; + + my $inner_target = caller; + my $export_data = sub_export_options($inner_target, @args); + + my $full_exporter; + no strict 'refs'; + @{"${inner_target}::EXPORT_OK"} = @{$export_data->{exports}}; + @{"${inner_target}::EXPORT"} = @{$export_data->{defaults}}; + %{"${inner_target}::EXPORT_TAGS"} = %{$export_data->{tags}}; + *{"${inner_target}::import"} = sub { + use strict; + my ($self, @args) = @_; + + if (List::Util::first { ref || !m/ \A [:-]? \w+ \z /xm } @args) { + Carp::croak 'your usage of Sub::Exporter::Progressive requires Sub::Exporter to be installed' + unless eval { require Sub::Exporter }; + $full_exporter ||= Sub::Exporter::build_exporter($export_data->{original}); + + goto $full_exporter; + } elsif (defined(my $num = List::Util::first { !ref and m/^\d/ } @args)) { + die "cannot export symbols with a leading digit: '$num'"; + } else { + require Exporter; + s/ \A - /:/xm for @args; + @_ = ($self, @args); + goto \&Exporter::import; + } + }; + return; +} + +my $too_complicated = <<'DEATH'; +You are using Sub::Exporter::Progressive, but the features your program uses from +Sub::Exporter cannot be implemented without Sub::Exporter, so you might as well +just use vanilla Sub::Exporter +DEATH + +sub sub_export_options { + my ($inner_target, $setup, $options) = @_; + + my @exports; + my @defaults; + my %tags; + + if ($setup eq '-setup') { + my %options = %$options; + + OPTIONS: + for my $opt (keys %options) { + if ($opt eq 'exports') { + + Carp::croak $too_complicated if ref $options{exports} ne 'ARRAY'; + @exports = @{$options{exports}}; + Carp::croak $too_complicated if List::Util::first { ref } @exports; + + } elsif ($opt eq 'groups') { + %tags = %{$options{groups}}; + for my $tagset (values %tags) { + Carp::croak $too_complicated if List::Util::first { / \A - (?! all \b ) /x || ref } @{$tagset}; + } + @defaults = @{$tags{default} || [] }; + } else { + Carp::croak $too_complicated; + } + } + @{$_} = map { / \A [:-] all \z /x ? @exports : $_ } @{$_} for \@defaults, values %tags; + $tags{all} ||= [ @exports ]; + my %exports = map { $_ => 1 } @exports; + my @errors = grep { not $exports{$_} } @defaults; + Carp::croak join(', ', @errors) . " is not exported by the $inner_target module\n" if @errors; + } + + return { + exports => \@exports, + defaults => \@defaults, + original => $options, + tags => \%tags, + }; +} + +1; + +=encoding utf8 + +=head1 NAME + +Sub::Exporter::Progressive - Only use Sub::Exporter if you need it + +=head1 SYNOPSIS + + package Syntax::Keyword::Gather; + + use Sub::Exporter::Progressive -setup => { + exports => [qw( break gather gathered take )], + groups => { + default => [qw( break gather gathered take )], + }, + }; + + # elsewhere + + # uses Exporter for speed + use Syntax::Keyword::Gather; + + # somewhere else + + # uses Sub::Exporter for features + use Syntax::Keyword::Gather 'gather', take => { -as => 'grab' }; + +=head1 DESCRIPTION + +L<Sub::Exporter> is an incredibly powerful module, but with that power comes +great responsibility, er- as well as some runtime penalties. This module +is a C<Sub::Exporter> wrapper that will let your users just use L<Exporter> +if all they are doing is picking exports, but use C<Sub::Exporter> if your +users try to use C<Sub::Exporter>'s more advanced features, like +renaming exports, if they try to use them. + +Note that this module will export C<@EXPORT>, C<@EXPORT_OK> and +C<%EXPORT_TAGS> package variables for C<Exporter> to work. Additionally, if +your package uses advanced C<Sub::Exporter> features like currying, this module +will only ever use C<Sub::Exporter>, so you might as well use it directly. + +=head1 AUTHOR + +frew - Arthur Axel Schmidt (cpan:FREW) <frioux+cpan@gmail.com> + +=head1 CONTRIBUTORS + +ilmari - Dagfinn Ilmari Mannsåker (cpan:ILMARI) <ilmari@ilmari.org> + +mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk> + +leont - Leon Timmermans (cpan:LEONT) <leont@cpan.org> + +=head1 COPYRIGHT + +Copyright (c) 2012 the Sub::Exporter::Progressive L</AUTHOR> and +L</CONTRIBUTORS> as listed above. + +=head1 LICENSE + +This library is free software and may be distributed under the same terms +as perl itself. + +=cut diff --git a/maint/Makefile.PL.include b/maint/Makefile.PL.include new file mode 100644 index 0000000..da4cf69 --- /dev/null +++ b/maint/Makefile.PL.include @@ -0,0 +1,7 @@ +BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") } +use lib 'Distar/lib'; +use Distar; + +author 'frew - Arthur Axel Schmidt (cpan:FREW) <frioux+cpan@gmail.com>'; + +1; @@ -0,0 +1,22 @@ + +use strict; +use warnings; + +use Test::More; +use List::Util 'first'; +use lib 't/lib'; +use A::JunkAll; + +ok(main->can('junk1'), 'sub exported'); +ok(main->can('junk2'), 'sub exported'); +ok(! $INC{'Sub/Exporter.pm'}, 'Sub::Exporter not loaded'); + +package Other; +use Test::More; +use A::JunkAll ':all'; + +ok(main->can('junk1'), 'sub exported'); +ok(main->can('junk2'), 'sub exported'); +ok(! $INC{'Sub/Exporter.pm'}, 'Sub::Exporter not loaded'); + +done_testing; diff --git a/t/basic.t b/t/basic.t new file mode 100644 index 0000000..5a841d1 --- /dev/null +++ b/t/basic.t @@ -0,0 +1,13 @@ + +use strict; +use warnings; + +use Test::More; +use List::Util 'first'; +use lib 't/lib'; +use A::Junk 'junk1'; + +ok(main->can('junk1'), 'requested sub exported'); +ok(! $INC{'Sub/Exporter.pm'}, 'Sub::Exporter not loaded'); + +done_testing; diff --git a/t/default.t b/t/default.t new file mode 100644 index 0000000..f7eb327 --- /dev/null +++ b/t/default.t @@ -0,0 +1,13 @@ + +use strict; +use warnings; + +use Test::More; +use List::Util 'first'; +use lib 't/lib'; +use A::Junk; + +ok(main->can('junk2'), 'sub exported'); +ok(! $INC{'Sub/Exporter.pm'}, 'Sub::Exporter not loaded'); + +done_testing; diff --git a/t/lib/A/Junk.pm b/t/lib/A/Junk.pm new file mode 100644 index 0000000..a5eab20 --- /dev/null +++ b/t/lib/A/Junk.pm @@ -0,0 +1,15 @@ +package A::Junk; + +use Sub::Exporter::Progressive -setup => { + exports => [qw(junk1 junk2 junk3)], + groups => { + default => ['junk2'], + other => ['junk3'], + }, +}; + +sub junk1 { 1 } +sub junk2 { 1 } +sub junk3 { 1 } + +1; diff --git a/t/lib/A/JunkAll.pm b/t/lib/A/JunkAll.pm new file mode 100644 index 0000000..d3e6123 --- /dev/null +++ b/t/lib/A/JunkAll.pm @@ -0,0 +1,13 @@ +package A::JunkAll; + +use Sub::Exporter::Progressive -setup => { + exports => [qw(junk1 junk2)], + groups => { + default => [ -all ], + }, +}; + +sub junk1 { 1 } +sub junk2 { 1 } + +1; @@ -0,0 +1,18 @@ + +use strict; +use warnings; + +use Test::More; +BEGIN { + plan skip_all => 'Sub::Exporter not installed' + unless eval { require Sub::Exporter }; +} + +use List::Util 'first'; +use lib 't/lib'; +use A::Junk 'junk1' => { -as => 'junk' }; + +ok(main->can('junk'), 'sub renamed with Sub::Exporter'); +ok($INC{'Sub/Exporter.pm'}, 'Sub::Exporter loaded'); + +done_testing; diff --git a/t/tags.t b/t/tags.t new file mode 100644 index 0000000..90f20ca --- /dev/null +++ b/t/tags.t @@ -0,0 +1,69 @@ +use strict; +use warnings; + +use Test::More; +use List::Util 'first'; +use Carp; +use lib 't/lib'; +use A::Junk ':other'; + +BEGIN { + unshift @INC, sub { croak 'Shouldn\'t load Sub::Exporter' if $_[1] eq 'Sub/Exporter.pm' }; +} + +ok(!main->can('junk1'), 'junk1 not exported'); +ok(!main->can('junk2'), 'junk2 not exported'); +ok(main->can('junk3'), 'junk3 exported'); +ok(! $INC{'Sub/Exporter.pm'}, 'Sub::Exporter not loaded'); + +BEGIN { + package Local::Exporter; + use Sub::Exporter::Progressive -setup => { + exports => [qw/ foo bar baz /], + groups => { + default => [qw/ foo /], + bb => [qw/ bar baz /], + }, + }; + use constant foo => 1; + use constant bar => 2; + use constant baz => 3; + + $INC{'Local/Exporter.pm'} = __FILE__; +}; + +my $i = 0; +sub check_tag { + my ($tag, $should, $shouldnt) = @_; + my $pkg = 'Local::Importer' . ++$i; + + ok(eval qq{ + package $pkg; + use Local::Exporter qw( $tag ); + 1; + }, "'$tag' tag: $pkg compiled") or diag $@; + + ok( $pkg->can($_), "'$tag' tag: $pkg\->can(\"$_\")") for @$should; + ok(!$pkg->can($_), "'$tag' tag: $pkg\->can't(\"$_\")") for @$shouldnt; +} + +check_tag(':default', [qw/foo/], [qw/bar baz/]); +check_tag('-default', [qw/foo/], [qw/bar baz/]); +check_tag(':default bar', [qw/foo bar/], [qw/baz/]); +check_tag('-default bar', [qw/foo bar/], [qw/baz/]); +check_tag(':bb', [qw/bar baz/], [qw/foo/]); +check_tag('-bb', [qw/bar baz/], [qw/foo/]); +check_tag(':all', [qw/foo bar baz/], []); +check_tag('-all', [qw/foo bar baz/], []); + +SKIP: { + skip "Your version of Exporter (@{[ Exporter->VERSION ]}) supports " + .'tags only as the first argument to import()', 1 + unless eval { Exporter->VERSION('5.58') }; + + check_tag('bar :default', [qw/foo bar/], [qw/baz/]); + check_tag('bar -default', [qw/foo bar/], [qw/baz/]); +} + +done_testing; + diff --git a/t/version-check.t b/t/version-check.t new file mode 100644 index 0000000..5fe1062 --- /dev/null +++ b/t/version-check.t @@ -0,0 +1,42 @@ + +use strict; +use warnings; +use Test::More; + +BEGIN { + package AAA; + our $VERSION = 2; + use Sub::Exporter::Progressive -setup => { + exports => ['aaa'], + }; + sub aaa { 'aaa' }; + $INC{'AAA.pm'} = __FILE__; +}; + +ok(eval('use AAA 1; 1'), 'perl built-in module version check'); + +{ + local $@; + ok(!eval('use AAA 3; 1'), 'perl built-in module version check'); + like( + $@, + qr/^AAA version 3 required/, + 'perl built-in module version check error message', + ); +} + +{ + local $@; + ok( + !eval('use AAA aaa => 1; 1'), + 'Exporter.pm-style version check', + ); + like( + $@, + qr{^cannot export symbols with a leading digit: '1'}, + 'Sub::Exporter::Progressive error message', + ); +} + +done_testing; + |