�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ� ���ͯj�ӣ��ƺ���ӣ� ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!README000064400000000476152527414730005445 0ustar00 This archive contains the distribution Sub-Exporter, version 0.987: a sophisticated exporter for custom-built routines This software is copyright (c) 2007 by Ricardo Signes. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. t/util-namemap.t000064400000001070152527414730007575 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More skip_all => 'not actually offerring this feature yet'; # use Test::More tests => 3; BEGIN { use_ok("Sub::Exporter::Util", 'name_map'); } is_deeply( { name_map( '_?_gen' => [ qw(fee fie) ], '_make_?' => [ qw(foo bar) ], ), }, { fee => \'_fee_gen', fie => \'_fie_gen', foo => \'_make_foo', bar => \'_make_bar', }, 'example from docs works just dandy', ); eval { name_map(foo => [ qw(bar) ] ) }; like($@, qr/no \?/, 'exception raised with no ? in template'); t/into-level.t000064400000006072152527414730007271 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests exercise the "into" and "into_level" special arguments to the built exporter. =cut use Test::More tests => 14; BEGIN { use_ok('Sub::Exporter'); } BEGIN { package Test::SubExport::FROM; use strict; use warnings; use Sub::Exporter -setup => { exports => [ qw(A B) ], groups => { default => [ ':all' ], a => [ 'A' ], b => [ 'B' ] } }; sub A { 'A' } sub B { 'B' } 1; } BEGIN { package Test::SubExport::HAS_DEFAULT_INTO_LEVEL; use strict; use warnings; use Sub::Exporter -setup => { exports => [ qw(C) ], into_level => 1, }; sub C { 'C' } 1; } BEGIN { package Test::SubExport::HAS_DEFAULT_INTO; use strict; use warnings; use Sub::Exporter -setup => { exports => [ qw(foo) ], into => 'Test::SubExport::DEFAULT_INTO', }; sub foo { 'foo' } 1; } BEGIN { package Test::SubExport::INTO; use strict; use warnings; sub import { my $package = shift; my $caller = caller(0); Test::SubExport::FROM->import( { into => $caller }, @_ ); } 1; } BEGIN { package Test::SubExport::LEVEL; use strict; use warnings; sub import { my $package = shift; Test::SubExport::FROM->import( { into_level => 1 }, @_ ); } 1; } BEGIN { package Test::SubExport::DEFAULT_LEVEL; use strict; use warnings; sub import { my $package = shift; Test::SubExport::HAS_DEFAULT_INTO_LEVEL->import(@_); } 1; } package Test::SubExport::INTO::A; Test::SubExport::INTO->import('A'); main::can_ok(__PACKAGE__, 'A' ); main::cmp_ok( __PACKAGE__->can('A'), '==', Test::SubExport::FROM->can('A'), 'sub A was exported' ); package Test::SubExport::INTO::ALL; Test::SubExport::INTO->import(':all'); main::can_ok(__PACKAGE__, 'A', 'B' ); main::cmp_ok( __PACKAGE__->can('A'), '==', Test::SubExport::FROM->can('A'), 'sub A was exported' ); main::cmp_ok( __PACKAGE__->can('B'), '==', Test::SubExport::FROM->can('B'), 'sub B was exported' ); package Test::SubExport::LEVEL::ALL; Test::SubExport::LEVEL->import(':all'); main::can_ok(__PACKAGE__, 'A', 'B' ); main::cmp_ok( __PACKAGE__->can('A'), '==', Test::SubExport::FROM->can('A'), 'sub A was exported' ); main::cmp_ok( __PACKAGE__->can('B'), '==', Test::SubExport::FROM->can('B'), 'sub B was exported' ); package Test::SubExport::LEVEL::DEFAULT; Test::SubExport::DEFAULT_LEVEL->import(':all'); main::can_ok(__PACKAGE__, 'C'); main::cmp_ok( __PACKAGE__->can('C'), '==', Test::SubExport::HAS_DEFAULT_INTO_LEVEL->can('C'), 'sub C was exported' ); package Test::SubExport::NON_DEFAULT_INTO; main::is( Test::SubExport::DEFAULT_INTO->can('foo'), undef, "before import, 'default into' target can't foo", ); Test::SubExport::HAS_DEFAULT_INTO->import('-all'); main::is( __PACKAGE__->can('foo'), undef, "after import, calling package can't foo", ); main::is( Test::SubExport::DEFAULT_INTO->can('foo'), \&Test::SubExport::HAS_DEFAULT_INTO::foo, "after import, calling package can't foo", ); t/collection.t000064400000005526152527414730007351 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests exercise the handling of collections in the exporter option lists. =cut use Test::More tests => 8; use Data::OptList qw(mkopt_hash); BEGIN { use_ok('Sub::Exporter'); } sub is_defined { my ($class, $value, $arg) = @_; return defined $value; } my $config = { exports => [ qw(circsaw drill handsaw nailgun), hammer => sub { sub { print "BANG BANG BANG\n" } }, ], groups => { default => [ 'handsaw', 'hammer' => { claw => 1 }, ], cutters => [ qw(circsaw handsaw), circsaw => { as => 'buzzsaw' } ], }, collectors => [ 'defaults', brand_preference => sub { 0 }, model_preference => sub { 1 }, sets_own_value => sub { $_[0] = { foo => 10 } }, definedp => \'is_defined', ] }; $config->{$_} = mkopt_hash($config->{$_}) for qw(exports collectors); { my $collection = Sub::Exporter::_collect_collections( $config, [ [ circsaw => undef ], [ defaults => { foo => 1, bar => 2 } ] ], 'main', ); is_deeply( $collection, { defaults => { foo => 1, bar => 2 } }, "collection returned properly from collector", ); } { my $collection = Sub::Exporter::_collect_collections( $config, [ [ sets_own_value => undef ] ], 'main', ); is_deeply( $collection, { sets_own_value => { foo => 10} }, "a collector can alter the stack to change its own value", ); } { my $arg = [ [ defaults => [ 1 ] ], [ defaults => { foo => 1, bar => 2 } ] ]; eval { Sub::Exporter::_collect_collections($config, $arg, 'main'); }; like( $@, qr/collection \S+ provided multiple/, "can't provide multiple collection values", ); } { # because the brand_preference validator always fails, this should die my $arg = [ [ brand_preference => [ 1, 2, 3 ] ] ]; eval { Sub::Exporter::_collect_collections($config, $arg, 'main') }; like( $@, qr/brand_preference failed validation/, "collector validator prevents bad export" ); } { # the definedp collector should require a defined value; this should be ok my $arg = [ [ definedp => {} ] ]; my $collection = Sub::Exporter::_collect_collections($config, $arg, 'main'); is_deeply( $collection, { definedp => {} }, "collector validator allows collection" ); } { # the definedp collector should require a defined value; this should die my $arg = [ [ definedp => undef ] ]; eval { Sub::Exporter::_collect_collections($config, $arg, 'main') }; like( $@, qr/definedp failed validation/, "collector validator prevents bad export" ); } { my $arg = [ [ model_preference => [ 1, 2, 3 ] ] ]; my $collection = Sub::Exporter::_collect_collections($config, $arg, 'main'); is_deeply( $collection, { model_preference => [ 1, 2, 3 ] }, "true-returning validator allows collection", ); } t/lib/Test/SubExporter/s_e.pm000064400000001402152527414730012071 0ustar00#!/usr/bin/perl package Test::SubExporter::s_e; use strict; use warnings; use Sub::Exporter; Sub::Exporter::setup_exporter({ exports => { xyzzy => undef, hello_sailor => \&_hs_gen, hi_sailor => \"_hs_gen", }, groups => { default => [ qw(xyzzy hello_sailor) ], sailor => [ xyzzy => undef, hello_sailor => { -as => 'hs_works', game => 'zork3' }, hello_sailor => { -as => 'hs_fails', game => 'zork1' }, ] }, collectors => [ 'defaults' ], }); sub xyzzy { return "Nothing happens." }; sub _hs_gen { my ($class, $name, $arg, $collection) = @_; if (($arg->{game}||'') eq 'zork3') { return sub { return "Something happens!" }; } else { return sub { return "Nothing happens yet." }; } } "y2"; t/lib/Test/SubExporter/ObjGen.pm000064400000001744152527414730012500 0ustar00#!/usr/bin/perl package Test::SubExporter::ObjGen::Obj; use strict; use warnings; sub new { my $class = shift; my $code = $class->can(shift); bless { code => $code } => $class; } sub group { return { foo => sub { return 'FOO' }, bar => sub { return 'BAR' }, }; } sub baz { return sub { return 'BAZ'; }; } use overload '&{}' => sub { $_[0]->{code} }, 'bool' => sub { 1 }; package Test::SubExporter::ObjGen; my ($group_o, $group_b, $baz, $quux); BEGIN { $quux = sub { sub { 'QUUX' } }; bless $quux => 'Test::SubExporter::Whatever'; $group_o = sub { return { ringo => sub { 'starr' }, richard => sub { 'starkey' }, } }; bless $group_o => 'Test::SubExporter::Whatever'; $baz = Test::SubExporter::ObjGen::Obj->new('baz'); $group_b = Test::SubExporter::ObjGen::Obj->new('group'); } use Sub::Exporter -setup => { exports => { baz => $baz, quux => $quux }, groups => { meta => $group_b, ringo => $group_o }, }; "call me"; t/lib/Test/SubExporter/DashSetup.pm000064400000001321152527414730013223 0ustar00#!/usr/bin/perl package Test::SubExporter::DashSetup; use strict; use warnings; use Sub::Exporter -setup => { exports => { xyzzy => undef, hello_sailor => \&_hs_gen, }, groups => { default => [ qw(xyzzy hello_sailor) ], sailor => [ xyzzy => undef, hello_sailor => { -as => 'hs_works', game => 'zork3' }, hello_sailor => { -as => 'hs_fails', game => 'zork1' }, ] }, collectors => [ 'defaults' ], }; sub xyzzy { return "Nothing happens." }; sub _hs_gen { my ($class, $name, $arg, $collection) = @_; if (($arg->{game}||'') eq 'zork3') { return sub { return "Something happens!" }; } else { return sub { return "Nothing happens yet." }; } } "y2"; t/lib/Test/SubExporter/GroupGen.pm000064400000002070152527414730013053 0ustar00#!/usr/bin/perl package Test::SubExporter::GroupGen; use strict; use warnings; use Sub::Exporter; my $alfa = sub { 'alfa' }; my $bravo = sub { 'bravo' }; my $returner = sub { my ($class, $group, $arg, $collection) = @_; my %given = ( class => $class, group => $group, arg => $arg, collection => $collection, ); return { foo => sub { return { name => 'foo', %given }; }, bar => sub { return { name => 'bar', %given }; }, }; }; sub gen_group_by_name { my ($class, $group, $arg, $collection) = @_; my %given = ( class => $class, group => $group, arg => $arg, collection => $collection, ); return { baz => sub { return { name => 'baz', %given }; }, }; } my $config = { exports => [ ], groups => { alphabet => sub { { a => $alfa, b => $bravo } }, generated => $returner, # symbolic => \&gen_group_by_name, # symbolic => sub { shift->gen_group_by_name(@_) }, symbolic => \'gen_group_by_name', }, collectors => [ 'col1' ], }; Sub::Exporter::setup_exporter($config); "gg"; t/lib/Test/SubExporter/Faux.pm000064400000003237152527414730012236 0ustar00 use strict; use warnings; package Test::SubExporter::Faux; use base qw(Exporter); our @EXPORT = qw(faux_installer exports_ok everything_ok); sub faux_installer { my ($verbose) = @_; $verbose = 1; my @exported; my $reset = sub { @exported = () }; my $generator = sub { my ($arg) = @_; # my ($class, $name, $generator) = @$arg{qw(class name generator)}; return $arg; }; my $installer = sub { my ($arg, $to_export) = @_; for (my $i = 0; $i < @$to_export; $i += 2) { my ($as, $gen_arg) = @$to_export[ $i, $i+1 ]; # my ($class, $generator, $name, $arg, $collection, $as, $into) = @_; my $everything = { class => $gen_arg->{class}, generator => $gen_arg->{generator}, name => $gen_arg->{name}, arg => $gen_arg->{arg}, collection => $gen_arg->{col}, as => $as, into => $arg->{into}, }; push @exported, [ $gen_arg->{name}, ($verbose ? $everything : $gen_arg->{arg}), ]; } }; return ($generator, $installer, $reset, \@exported); } sub exports_ok { my ($got, $expected, $comment) = @_; my $got_simple = [ map { [ $_->[0], $_->[1]{arg} ] } @$got ]; my @g = sort { ($a->[0] cmp $b->[0]) || ($a->[1] <=> $b->[1]) } @$got_simple; my @e = sort { ($a->[0] cmp $b->[0]) || ($a->[1] <=> $b->[1]) } @$expected; main::is_deeply(\@e, \@g, $comment); } sub everything_ok { my ($got, $expected, $comment) = @_; my @g = sort { ($a->[0] cmp $b->[0]) || ($a->[1] <=> $b->[1]) } @$got; my @e = sort { ($a->[0] cmp $b->[0]) || ($a->[1] <=> $b->[1]) } @$expected; main::is_deeply(\@e, \@g, $comment); } 1; t/lib/Test/SubExporter/GroupGenSubclass.pm000064400000000617152527414730014560 0ustar00use strict; use warnings; package Test::SubExporter::GroupGenSubclass; use base qw(Test::SubExporter::GroupGen); sub gen_group_by_name { my ($class, $group, $arg, $collection) = @_; my %given = ( class => $class, group => $group, arg => $arg, collection => $collection, ); return { baz => sub { return { name => 'baz-sc', %given }; }, }; } "power overwhelming"; t/valid-config.t000064400000002431152527414730007550 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests make sure that invalid configurations passed to setup/build_exporter throw exceptions. =cut use Test::More tests => 6; BEGIN { use_ok('Sub::Exporter'); } eval { Sub::Exporter::build_exporter({ exports => [ qw(foo) ], collectors => [ qw(foo) ], }) }; like($@, qr/used in both/, "can't use one name in exports and collectors"); eval { Sub::Exporter::build_exporter({ collections => [ qw(foo) ], # This one gets me all the time. Live & learn. }) }; like($@, qr/unknown options/, "unknown options raise an exception"); eval { Sub::Exporter::setup_exporter({ into => 'Your::Face', into_level => 5, }) }; like( $@, qr/may not both/, "into and into_level are mutually exclusive (in setup_exporter)" ); eval { Sub::Exporter::build_exporter({})->( Class => { into => 'Your::Face', into_level => 1 } ); }; like( $@, qr/may not both/, "into and into_level are mutually exclusive (in exporter)" ); eval { Sub::Exporter::build_exporter({ into => "This::Doesnt::Matter", into_level => 0, }) }; like( $@, qr(^into and into_level may not both be supplied to exporter), "can't use one name in exports and collectors" ); t/real-export-href.t000064400000010177152527414730010400 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests exercise the use of Sub::Exporter via its setup_exporter routine. They use Test::SubExporter::s_e, bundled in ./t/lib, which uses this calling style. =cut use Test::More tests => 48; BEGIN { use_ok('Sub::Exporter'); } our $exporting_class = 'Test::SubExporter::s_e'; use lib 't/lib'; for my $iteration (1..2) { { package Test::SubExporter::BUILT; my $import = Sub::Exporter::build_exporter({ exports => [ 'X' ] }); Sub::Exporter::setup_exporter({ exports => [ 'X' ], into => 'Test::SubExporter::VIOLATED' . "_$iteration", as => 'gimme_X_from', }); sub X { return "expected" } package Test::SubExporter::BUILT::CONSUMER; $import->('Test::SubExporter::BUILT', ':all'); main::is(X(), "expected", "manually constructed importer worked"); eval < { -as => 'plugh' }); use subs qw(plugh); main::is( plugh, "Nothing happens.", "RENAME: default export xyzzy=>plugh works as expected" ); package Test::SubExporter::SAILOR; main::use_ok($exporting_class, ':sailor'); use subs qw(xyzzy hs_works hs_fails); main::is( xyzzy, "Nothing happens.", "SAILOR: default export xyzzy works as expected" ); main::is( hs_works, "Something happens!", "SAILOR: hs_works export works as expected" ); main::is( hs_fails, "Nothing happens yet.", "SAILOR: hs_fails export works as expected" ); package Test::SubExporter::Z3; main::use_ok( $exporting_class, hello_sailor => { game => 'zork3' }, hi_sailor => undef, ); use subs qw(hello_sailor hi_sailor); main::is( hello_sailor, "Something happens!", "Z3: custom hello_sailor works as expected" ); main::is( hi_sailor, "Nothing happens yet.", "Z3: hi_sailor, using symbolic import and no args, works as expected" ); package Test::SubExporter::FROTZ_SAILOR; main::use_ok($exporting_class, -sailor => { -prefix => 'frotz_' }); use subs map { "frotz_$_" }qw(xyzzy hs_works hs_fails); main::is( frotz_xyzzy, "Nothing happens.", "FROTZ_SAILOR: default export xyzzy works as expected" ); main::is( frotz_hs_works, "Something happens!", "FROTZ_SAILOR: hs_works export works as expected" ); main::is( frotz_hs_fails, "Nothing happens yet.", "FROTZ_SAILOR: hs_fails export works as expected" ); package Test::SubExporter::Z3_REF; my $hello; main::use_ok( $exporting_class, hello_sailor => { game => 'zork3', -as => \$hello } ); eval "hello_sailor;"; main::like( $@, qr/Bareword "hello_sailor" not allowed/, "Z3_REF: hello_sailor isn't actually imported to package" ); main::is( $hello->(), "Something happens!", "Z3_REF: hello_sailor properly exported to scalar ref", ); package Test::SubExporter::Z3_BADREF; main::require_ok($exporting_class); eval { Test::SubExporter::s_e->import(hello_sailor => { game => 'zork3', -as => {} }); }; main::like( $@, qr/invalid reference type/, "can't pass a non-scalar ref to -as", ); } sub install_upstream { Sub::Exporter::setup_exporter({ exports => [ 'X' ], as => 'gimme_X_from', into_level => 1, }); } package Test::SubExporter::LEVEL_1; sub X { return 1 }; main::install_upstream; package Test::SubExporter::CALLS_LEVEL_1; Test::SubExporter::LEVEL_1->gimme_X_from(X => { -as => 'x_from_1' }); use subs 'x_from_1'; main::is(x_from_1(), 1, "imported from uplevel-installed exporter"); t/util-mixin.t000064400000005353152527414730007313 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More; BEGIN { if (eval { require Package::Generator; 1; }) { plan 'no_plan'; } else { plan skip_all => "the mixin exporter requires Package::Generator"; } } BEGIN { use_ok("Sub::Exporter"); } BEGIN { package Thing; use Sub::Exporter -setup => { exports => { bar => sub { sub { 1 } }, foo => sub { my ($c, $n, $a) = @_; sub { return $c . ($a->{arg}) } } }, }; } BEGIN { package Thing::Mixin; BEGIN { main::use_ok("Sub::Exporter::Util", 'mixin_installer'); } use Sub::Exporter -setup => { installer => mixin_installer, exports => { bar => sub { sub { 1 } }, foo => sub { my ($c, $n, $a) = @_; sub { return $c . ($a->{arg}) } } }, }; } package Test::SubExporter::MIXIN::0; BEGIN { Thing->import( { installer => Sub::Exporter::Util::mixin_installer }, -all => { arg => '0' }, ); } package Test::SubExporter::MIXIN::1; BEGIN { Thing->import( { installer => Sub::Exporter::Util::mixin_installer }, -all => { arg => '1' }, ); } package Test::SubExporter::MIXIN::2; BEGIN { Thing::Mixin->import( -all => { arg => '2' }, ); } package Test::SubExporter::MIXIN::3; BEGIN { Thing::Mixin->import( -all => { arg => '3' }, ); } package main; my @pkg = map { "Test::SubExporter::MIXIN::$_" } (0 .. 3); for (0 .. $#pkg) { my $ext = $_ > 1 ? '::Mixin' : ''; my $val = eval { $pkg[$_]->foo } || ($@ ? "died: $@" : undef); is( $val, "Thing$ext$_", "mixed in method in $pkg[$_] returns correctly" ); is($pkg[$_]->bar, 1, "bar method for $pkg[$_] is ok, too"); } my @super = map {; no strict 'refs'; [ @{$_ . "::ISA"} ] } @pkg; for my $x (0 .. $#pkg) { is(@{$super[$x]}, 1, "one parent for $pkg[$x]: @{$super[$x]}"); for my $y (($x + 1) .. $#pkg) { isnt("@{$super[$x]}", "@{$super[$y]}", "parent($x) ne parent($y)") } } { package Test::SubExporter::OBJECT; sub new { bless {} => shift } sub plugh { "plugh" } } package main; my $obj_1 = Test::SubExporter::OBJECT->new; isa_ok($obj_1, "Test::SubExporter::OBJECT", "first object"); is(ref $obj_1, "Test::SubExporter::OBJECT", "first object's ref is TSEO"); my $obj_2 = Test::SubExporter::OBJECT->new; isa_ok($obj_2, "Test::SubExporter::OBJECT", "second object"); is(ref $obj_2, "Test::SubExporter::OBJECT", "second object's ref is TSEO"); Thing::Mixin->import({ into => $obj_1 }, qw(bar)); pass("mixin-exporting to an object didn't die"); is( eval { $obj_1->bar }, 1, "now that object has a bar method" ); isa_ok($obj_1, "Test::SubExporter::OBJECT"); isnt(ref $obj_1, "Test::SubExporter::OBJECT", "but its actual class isnt TSEO"); t/col-init.t000064400000002201152527414730006717 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests exercise the handling of collections in the exporter option lists. =cut use Test::More tests => 3; use Data::OptList qw(mkopt_hash); BEGIN { use_ok('Sub::Exporter'); } sub is_defined { my ($class, $value, $arg) = @_; return defined $value; } my $counter = 0; my $config = { exports => [ qw(circsaw drill handsaw nailgun) ], collectors => [ INIT => sub { my ($value, $arg) = @_; return 0 if @{$arg->{import_args}}; # in other words, fail if args $_[0] = [ $counter++ ]; return 1; }, ] }; $config->{$_} = mkopt_hash($config->{$_}) for qw(exports collectors); { my $collection = Sub::Exporter::_collect_collections( $config, [ ], 'main', ); is_deeply( $collection, { INIT => [ 0 ] }, "collection returned properly from collector", ); } { my $collection = eval { Sub::Exporter::_collect_collections( $config, [ [ handsaw => undef ] ], 'main', ); }; like( $@, qr/INIT failed/, "the init collector is run even when other things are here", ); } t/faux-export.t000064400000005744152527414730007502 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests check the output of build_installer when handed an alternate installer that returns its plan. =cut use Test::More tests => 11; BEGIN { use_ok('Sub::Exporter'); } use lib 't/lib'; use Test::SubExporter::Faux; my $config = { exports => [ qw(circsaw drill handsaw nailgun), hammer => sub { sub { print "BANG BANG BANG\n" } }, ], groups => { default => [ 'handsaw', 'hammer' => { claw => 1 }, ], cutters => [ qw(circsaw handsaw), circsaw => { -as => 'buzzsaw' } ], }, collectors => [ 'defaults', 'brand_preference' => sub { 0 }, ] }; { my ($generator, $installer, $reset, $exports) = faux_installer; my $code = sub { $reset->(); splice @_, 1, 0, { generator => $generator, installer => $installer }; Sub::Exporter::build_exporter($config)->(@_); }; $code->('Tools::Power'); exports_ok( $exports, [ [ handsaw => {} ], [ hammer => { claw => 1 } ] ], "exporting with no arguments gave us default group" ); $code->('Tools::Power', ':all'); exports_ok( [ sort { $a->[0] cmp $b->[0] } @$exports ], [ map { [ $_ => {} ] } sort qw(circsaw drill handsaw nailgun hammer), ], "exporting :all gave us all exports", ); $code->('Tools::Power', drill => { -as => 'auger' }); exports_ok( $exports, [ [ drill => {} ] ], "'-as' parameter is not passed to generators", ); $code->('Tools::Power', ':cutters'); exports_ok( $exports, [ [ circsaw => {} ], [ handsaw => {} ], [ circsaw => {} ] ], "group with two export instances of one export", ); eval { $code->('Tools::Power', 'router') }; like($@, qr/not exported/, "can't export un-exported export (got that?)"); eval { $code->('Tools::Power', ':sockets') }; like($@, qr/not exported/, "can't export nonexistent group, either"); # because the brand_preference validator always fails, this should die eval { $code->('Tools::Power', brand_preference => [ '...' ]) }; like( $@, qr/brand_preference failed validation/, "collector validator prevents bad export" ); } { my ($generator, $installer, $reset, $exports) = faux_installer; my $code = sub { $reset->(); splice @_, 1, 0, { generator => $generator, installer => $installer }; Sub::Exporter::build_exporter({ exports => [ 'foo' ] })->(@_); }; $code->('Example::Foo'); exports_ok( $exports, [ ], "exporting with no arguments gave us default default group, i.e., nothing" ); $code->('Tools::Power', ':all'); exports_ok( $exports, [ [ foo => {} ] ], "exporting :all gave us all exports, i.e., foo", ); } { package Test::SubExport::FAUX; my ($generator, $installer, $reset, $exports) = main::faux_installer; Sub::Exporter::setup_exporter({ exports => [ 'X' ], installer => $installer, generator => $generator, }); __PACKAGE__->import(':all'); main::exports_ok($exports, [ [ X => {} ] ], "setup (not built) exporter"); } t/util-merge.t000064400000003330152527414730007257 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More tests => 8; BEGIN { use_ok("Sub::Exporter"); } BEGIN { package Thing; BEGIN { main::use_ok("Sub::Exporter::Util", 'merge_col'); } use Sub::Exporter -setup => { collectors => [ qw(defaults etc) ], exports => { merge_col( defaults => { stack => sub { my @x = @_; sub { return @x } }, kcats => \'_kcats_gen', }, empty => { bogus => sub { my @x = @_; sub { return @x } }, klame => sub { my @x = @_; sub { return @x } }, }, etc => { other => sub { my @x = @_; sub { return @x } }, }, ), plain => sub { my @x = @_; sub { return @x } }, }, }; sub _kcats_gen { my @x = @_; sub { return reverse @x } } } package Test::SubExporter::MERGE::0; my %col; BEGIN { Thing->import( defaults => ($col{defaults} = { x => 10 }), etc => ($col{etc} = { home => "Kansas" }), stack => { x => 20, y => 30 }, kcats => { y => 3 }, bogus => undef, klame => { bar => 99 }, other => undef, plain => { foo => 10 }, ); } my %tests = ( stack => [ 'Thing', 'stack', { x => 20, y => 30 }, \%col ], kcats => [ \%col, { x => 10, y => 3 }, 'kcats', 'Thing' ], bogus => [ 'Thing', 'bogus', {}, \%col ], klame => [ 'Thing', 'klame', { bar => 99 }, \%col ], other => [ 'Thing', 'other', { home => "Kansas" }, \%col ], plain => [ 'Thing', 'plain', { foo => 10 }, \%col ], ); while (my ($name, $expected) = each %tests) { main::is_deeply( [ __PACKAGE__->$name ], $expected, "$name returned proper value", ); } t/000-report-versions-tiny.t000064400000005074152527414730011653 0ustar00use strict; use warnings; use Test::More 0.88; # This is a relatively nice way to avoid Test::NoWarnings breaking our # expectations by adding extra tests, without using no_plan. It also helps # avoid any other test module that feels introducing random tests, or even # test plans, is a nice idea. our $success = 0; END { $success && done_testing; } # List our own version used to generate this my $v = "\nGenerated by Dist::Zilla::Plugin::ReportVersions::Tiny v1.10\n"; eval { # no excuses! # report our Perl details my $want = '5.006'; $v .= "perl: $] (wanted $want) on $^O from $^X\n\n"; }; defined($@) and diag("$@"); # Now, our module version dependencies: sub pmver { my ($module, $wanted) = @_; $wanted = " (want $wanted)"; my $pmver; eval "require $module;"; if ($@) { if ($@ =~ m/Can't locate .* in \@INC/) { $pmver = 'module not found.'; } else { diag("${module}: $@"); $pmver = 'died during require.'; } } else { my $version; eval { $version = $module->VERSION; }; if ($@) { diag("${module}: $@"); $pmver = 'died during VERSION check.'; } elsif (defined $version) { $pmver = "$version"; } else { $pmver = ''; } } # So, we should be good, right? return sprintf('%-45s => %-10s%-15s%s', $module, $pmver, $wanted, "\n"); } eval { $v .= pmver('Carp','any version') }; eval { $v .= pmver('Data::OptList','0.100') }; eval { $v .= pmver('Exporter','any version') }; eval { $v .= pmver('ExtUtils::MakeMaker','6.30') }; eval { $v .= pmver('File::Spec','any version') }; eval { $v .= pmver('IO::Handle','any version') }; eval { $v .= pmver('IPC::Open3','any version') }; eval { $v .= pmver('Params::Util','0.14') }; eval { $v .= pmver('Sub::Install','0.92') }; eval { $v .= pmver('Test::More','0.96') }; eval { $v .= pmver('base','any version') }; eval { $v .= pmver('lib','any version') }; eval { $v .= pmver('overload','any version') }; eval { $v .= pmver('strict','any version') }; eval { $v .= pmver('subs','any version') }; eval { $v .= pmver('warnings','any version') }; # All done. $v .= <<'EOT'; Thanks for using my code. I hope it works for you. If not, please try and include this output in the bug report. That will help me reproduce the issue and solve your problem. EOT diag($v); ok(1, "we really didn't test anything, just reporting data"); $success = 1; # Work around another nasty module on CPAN. :/ no warnings 'once'; $Template::Test::NO_FLUSH = 1; exit 0; t/expand-group.t000064400000012430152527414730007617 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests check export group expansion, name prefixing, and option merging. =cut use Test::More tests => 55; BEGIN { use_ok('Sub::Exporter'); } my $import_target; my $config = { exports => [ qw(a b c) ], groups => { A => [ 'a' ], B => [ qw(b c) ], C => [ qw(a b :C) ], D => [ qw(:A :B) ], a_as_b => [ a => { -as => 'b' } ], prefixed_A => [ -A => { -prefix => 'alfa_' } ], suffixed_A => [ -A => { -suffix => '_yankee' } ], diprefixed_A => [ -prefixed_A => { -prefix => 'bravo_' } ], disuffixed_A => [ -suffixed_A => { -suffix => '_zulu' } ], presuffixed_A=> [ -A => { -prefix => 'freakin_', -suffix => '_right' } ], a_to_subref => [ a => { -as => \$import_target }, 'b' ], prefixed_a_s => [ -a_to_subref => { -prefix => 'alfa_' } ], } }; my @single_tests = ( [ "simple group 1", [ ':A' => undef ] => [ [ a => undef ] ] ], [ "simple group 2", [ ':B' => undef ] => [ [ b => undef ], [ c => undef ] ] ], [ "group of groups", [ ':D' => undef ], [ [ a => undef ], [ b => undef ], [ c => undef ] ], ], [ "recursive group", [ ':C' => undef ], [ [ a => undef ], [b => undef ] ], ], [ "group with empty args", [ -A => { } ], [ [ a => undef ] ], ], [ "group with prefix", [ -A => { -prefix => 'alpha_' } ], [ [ a => { -as => 'alpha_a' } ] ], ], [ "group with suffix", [ -A => { -suffix => '_import' } ], [ [ a => { -as => 'a_import' } ] ], ], [ "recursive group with prefix", [ -C => { -prefix => 'kappa_' } ], [ [ a => { -as => 'kappa_a' } ], [ b => { -as => 'kappa_b' } ] ], ], [ "recursive group with suffix", [ -C => { -suffix => '_etc' } ], [ [ a => { -as => 'a_etc' } ], [ b => { -as => 'b_etc' } ] ], ], [ "group that renames", [ -a_as_b => undef ], [ [ a => { -as => 'b' } ] ], ], [ "group that renames, with options", [ -a_as_b => { foo => 10 } ], [ [ a => { -as => 'b', foo => 10 } ] ], ], [ "group that renames, with a prefix", [ -a_as_b => { -prefix => 'not_really_' } ], [ [ a => { -as => 'not_really_b' } ] ], ], [ "group that renames, with a suffix", [ -a_as_b => { -suffix => '_or_not' } ], [ [ a => { -as => 'b_or_not' } ] ], ], [ "group that renames, with a prefix and suffix", [ -a_as_b => { -prefix => 'not_really_' } ], [ [ a => { -as => 'not_really_b' } ] ], ], [ "recursive group with a built-in prefix", [ -prefixed_A => undef ], [ [ a => { -as => 'alfa_a' } ] ], ], [ "recursive group with built-in and passed-in prefix", [ -prefixed_A => { -prefix => 'bravo_' } ], [ [ a => { -as => 'bravo_alfa_a' } ] ], ], [ "recursive group with built-in and passed-in suffix", [ -suffixed_A => { -suffix => '_zulu' } ], [ [ a => { -as => 'a_yankee_zulu' } ] ], ], [ "multi-prefixed group", [ -diprefixed_A => undef ], [ [ a => { -as => 'bravo_alfa_a' } ] ], ], [ "multi-suffixed group", [ -disuffixed_A => undef ], [ [ a => { -as => 'a_yankee_zulu' } ] ], ], [ "multi-prefixed group with prefix", [ -diprefixed_A => { -prefix => 'charlie_' } ], [ [ a => { -as => 'charlie_bravo_alfa_a' } ] ], ], [ "group with built-in prefix and suffix", [ -presuffixed_A => undef ], [ [ a => { -as => 'freakin_a_right' } ] ], ], [ "group with built-in prefix and suffix, plus prefix", [ -presuffixed_A => { -prefix => 'totally_' } ], [ [ a => { -as => 'totally_freakin_a_right' } ] ], ], [ "group with built-in prefix and suffix, plus suffix", [ -presuffixed_A => { -suffix => '_dude' } ], [ [ a => { -as => 'freakin_a_right_dude' } ] ], ], [ "group with built-in prefix and suffix, plus prefix and suffix", [ -presuffixed_A => { -prefix => 'totally_', -suffix => '_dude' } ], [ [ a => { -as => 'totally_freakin_a_right_dude' } ] ], ], [ "group that exports to scalar (unusual)", [ -a_to_subref => undef ], [ [ a => { -as => \$import_target } ], [ b => undef ] ], ], [ "group that exports to scalar, with prefix", [ -a_to_subref => { -prefix => 'jubju' } ], [ [ a => { -as => \$import_target } ], [ b => { -as => 'jubjub' } ] ], ], ); for my $test (@single_tests) { my ($label, $given, $expected) = @$test; my @got = Sub::Exporter::_expand_group( 'Class', $config, $given, {}, ); is_deeply(\@got, $expected, "expand_group: $label"); } for my $test (@single_tests) { my ($label, $given, $expected) = @$test; my $got = Sub::Exporter::_expand_groups( 'Class', $config, [ $given ], ); is_deeply($got, $expected, "expand_groups: $label [single test]"); } my @multi_tests = ( [ "group and export", [ [ ':A', undef ], [ c => undef ] ], [ [ a => undef ], [ c => undef ] ] ], [ "two groups with different merges", [ [ -A => { -prefix => 'A_' } ], [ -prefixed_A => { -suffix => '_p' } ] ], [ [ a => { -as => 'A_a' } ], [ a => { -as => 'alfa_a_p' } ], ] ], ); for my $test (@multi_tests) { my ($label, $given, $expected) = @$test; my $got = Sub::Exporter::_expand_groups( 'Class', $config, $given, ); is_deeply($got, $expected, "expand_groups: $label"); } t/real-export-setup.t000064400000007143152527414730010613 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests exercise that the polymorphic exporter-builder used when Sub::Exporter's -import group is invoked. They use Test::SubExporter::DashSetup, bundled in ./t/lib, which uses this calling style. =cut use Test::More tests => 40; BEGIN { use_ok('Sub::Exporter'); } our $exporting_class = 'Test::SubExporter::DashSetup'; use lib 't/lib'; for my $iteration (1..2) { { package Test::SubExporter::SETUP; use Sub::Exporter -setup => [ qw(X) ]; sub X { return "desired" } package Test::SubExporter::SETUP::CONSUMER; Test::SubExporter::SETUP->import(':all'); main::is(X(), "desired", "constructed importer (via -setup [LIST]) worked"); } { package Test::SubExporter::EXPORT_MISSING; use Sub::Exporter -setup => [ qw(X) ]; package Test::SubExporter::SETUP::CONSUMER_OF_MISSING; eval { Test::SubExporter::EXPORT_MISSING->import(':all') }; main::like( $@, qr/can't locate export/, "croak if we're configured to export something that can't be found", ); } { package Test::SubExporter::SETUPFAILURE; eval { Sub::Exporter->import( -setup => sub { 1 }) }; main::like($@, qr/-setup failed validation/, "only [],{} ok for -setup"); } package Test::SubExporter::DEFAULT; main::use_ok($exporting_class); use subs qw(xyzzy hello_sailor); main::is( xyzzy, "Nothing happens.", "DEFAULT: default export xyzzy works as expected" ); main::is( hello_sailor, "Nothing happens yet.", "DEFAULT: default export hello_sailor works as expected" ); package Test::SubExporter::RENAME; main::use_ok($exporting_class, xyzzy => { -as => 'plugh' }); use subs qw(plugh); main::is( plugh, "Nothing happens.", "RENAME: default export xyzzy=>plugh works as expected" ); package Test::SubExporter::SAILOR; main::use_ok($exporting_class, ':sailor');; use subs qw(xyzzy hs_works hs_fails); main::is( xyzzy, "Nothing happens.", "SAILOR: default export xyzzy works as expected" ); main::is( hs_works, "Something happens!", "SAILOR: hs_works export works as expected" ); main::is( hs_fails, "Nothing happens yet.", "SAILOR: hs_fails export works as expected" ); package Test::SubExporter::Z3; main::use_ok($exporting_class, hello_sailor => { game => 'zork3' }); use subs qw(hello_sailor); main::is( hello_sailor, "Something happens!", "Z3: custom hello_sailor works as expected" ); package Test::SubExporter::FROTZ_SAILOR; main::use_ok($exporting_class, -sailor => { -prefix => 'frotz_' }); use subs map { "frotz_$_" }qw(xyzzy hs_works hs_fails); main::is( frotz_xyzzy, "Nothing happens.", "FROTZ_SAILOR: default export xyzzy works as expected" ); main::is( frotz_hs_works, "Something happens!", "FROTZ_SAILOR: hs_works export works as expected" ); main::is( frotz_hs_fails, "Nothing happens yet.", "FROTZ_SAILOR: hs_fails export works as expected" ); } { package Test::SubExporter::SETUPALT; use Sub::Exporter -setup => { -as => 'alternimport', exports => [ qw(Y) ], }; sub X { return "desired" } sub Y { return "other" } package Test::SubExporter::SETUP::ALTCONSUMER; Test::SubExporter::SETUPALT->import(':all'); eval { X() }; main::like($@, qr/undefined subroutine/i, "X didn't get imported"); eval { Y() }; main::like($@, qr/undefined subroutine/i, "Y didn't get imported"); Test::SubExporter::SETUPALT->alternimport(':all'); main::is(Y(), "other", "other importer (via -setup { -as ...}) worked"); } t/inherited.t000064400000001145152527414730007162 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests check that the inherited form of a routine is the exported one. =cut use Test::More tests => 3; BEGIN { use_ok('Sub::Exporter'); } package E::Parent; use Sub::Exporter -setup => { exports => [ qw(foo) ] }; sub foo { return 1; } package E::Child; use base qw(E::Parent); sub foo { return 2; } package Test::Sub::Exporter::EPARENT; E::Parent->import('foo'); main::is(foo(), 1, "get result of parent's import"); package Test::Sub::Exporter::ECHILD; E::Child->import('foo'); main::is(foo(), 2, "get result of child's import"); t/00-compile.t000064400000001733152527414730007057 0ustar00use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::Compile 2.037 use Test::More 0.94 tests => 2; my @module_files = ( 'Sub/Exporter.pm', 'Sub/Exporter/Util.pm' ); # no fake home requested my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib'; use File::Spec; use IPC::Open3; use IO::Handle; my @warnings; for my $lib (@module_files) { # see L open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!"; my $stderr = IO::Handle->new; my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]"); binmode $stderr, ':crlf' if $^O eq 'MSWin32'; my @_warnings = <$stderr>; waitpid($pid, 0); is($?, 0, "$lib loaded ok"); if (@_warnings) { warn @_warnings; push @warnings, @_warnings; } } # no warning checks; BAIL_OUT("Compilation problems") if !Test::More->builder->is_passing; t/gen-callable.t000064400000001076152527414730007520 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More tests => 8; use lib 't/lib'; BEGIN { use_ok("Sub::Exporter"); use_ok("Test::SubExporter::ObjGen", 'baz', '-meta', 'quux', '-ringo'); } is(quux(), 'QUUX', 'blessed coderef generator'); is(baz(), 'BAZ', 'object with &{} as generator'); is(foo(), 'FOO', 'object with &{} as group generator (1/2)'); is(bar(), 'BAR', 'object with &{} as group generator (2/2)'); is(ringo(), 'starr', 'blessed coderef as group generator (1/2)'); is(richard(), 'starkey', 'blessed coderef as group generator (2/2)'); t/util-currychain.t000064400000003266152527414730010337 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More tests => 4; BEGIN { use_ok("Sub::Exporter::Util", qw(curry_chain)); } # So, some packages that we'll chain methods through. { package Test::CurryChain::Head; sub new { my ($class, @arg) = @_; bless [ @arg ] => $class; } sub next_obj { shift; return Test::CurryChain::Tail->new(@_); } sub false { return; } sub non_invocant { return 1; } package Test::CurryChain::Tail; sub new { my ($class, @arg) = @_; bless [ @arg ] => $class; } sub rev_guts { return reverse @{shift()}; } } { # Then the generator which could be put into a Sub::Exporter -setup. # This is an optlist. AREF = args; undef = no args; CODE = args generator my $generator = curry_chain( next_obj => [ 1, 2, 3 ], rev_guts => undef, ); my $curried_sub = $generator->('Test::CurryChain::Head'); my @result = $curried_sub->(); is_deeply( \@result, [ 3, 2, 1], "simple curried chain behaves as expected" ); } { # This one will fail, beacuse the second call returns false. my $generator = curry_chain( new => [ 1, 2, 3 ], false => undef, will_fail => undef, ); my $curried_sub = $generator->('Test::CurryChain::Head'); eval { $curried_sub->() }; like($@, qr/can't call will_fail/, "exception on broken chain"); } { # This one will fail, beacuse the second call returns a true non-invocant. my $generator = curry_chain( new => [ 1, 2, 3 ], non_invocant => undef, will_fail => undef, ); my $curried_sub = $generator->('Test::CurryChain::Head'); eval { $curried_sub->() }; like($@, qr/can't call will_fail/, "exception on broken chain"); } t/util-curry.t000064400000003307152527414730007330 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More tests => 10; BEGIN { use_ok("Sub::Exporter"); } BEGIN { package Thing; BEGIN { main::use_ok('Sub::Exporter::Util', 'curry_class'); } use Sub::Exporter -setup => { exports => { return_invocant => curry_class, talkback => curry_class('return_invocant'), }, }; sub new { bless { key => "value" } => $_[0] } sub return_invocant { return $_[0] } } BEGIN { package Thing::Subclass; our @ISA = qw(Thing); } package Test::SubExporter::CURRY::0; BEGIN { Thing->import(qw(return_invocant)); } main::is( Thing->return_invocant, "Thing", "method call on Thing returns Thing", ); main::is( Thing::Subclass->return_invocant, "Thing::Subclass", "method call on Thing::Subclass returns Thing::Subclass", ); main::is( return_invocant(), 'Thing', 'return of method class-curried from Thing is Thing' ); package Test::SubExporter::CURRY::1; BEGIN { Thing::Subclass->import(qw(return_invocant)); } main::is( Thing->return_invocant, "Thing", "method call on Thing returns Thing", ); main::is( Thing::Subclass->return_invocant, "Thing::Subclass", "method call on Thing::Subclass returns Thing::Subclass", ); main::is( return_invocant(), 'Thing::Subclass', 'return of method class-curried from Thing::Subclass is Thing::Subclass' ); package Test::SubExporter::CURRY::2; BEGIN { Thing->import(qw(talkback)); } main::is( talkback(), 'Thing', 'imported talkback acts like return_invocant' ); package Test::SubExporter::CURRY::Object; BEGIN { Thing->new->import(qw(talkback)); } main::isa_ok( talkback(), 'Thing', 'the result of object-curried talkback' ); t/real-export-groupgen.t000064400000003556152527414730011305 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests check export group expansion, specifically the expansion of groups that use group generators, more specifically when actually imported. =cut use Test::More tests => 8; use lib 't/lib'; use Carp; BEGIN { local $SIG{__DIE__} = sub { Carp::confess @_ }; use_ok('Test::SubExporter::GroupGen'); Test::SubExporter::GroupGen->import( col1 => { value => 2 }, -generated => { xyz => 1 }, -generated => { xyz => 5, -prefix => 'five_' }, -symbolic => { xyz => 2 }, ); use_ok('Test::SubExporter::GroupGenSubclass'); Test::SubExporter::GroupGenSubclass->import( col1 => { value => 3 }, -symbolic => { -prefix => 'subclass_', xyz => 4 }, ); } for my $routine (qw(foo bar)) { is_deeply( main->$routine(), { name => $routine, class => 'Test::SubExporter::GroupGen', group => 'generated', arg => { xyz => 1 }, collection => { col1 => { value => 2 } }, }, "generated $routine does what we expect", ); my $five = "five_$routine"; is_deeply( main->$five(), { name => $routine, class => 'Test::SubExporter::GroupGen', group => 'generated', arg => { xyz => 5 }, collection => { col1 => { value => 2 } }, }, "generated $five does what we expect", ); } is_deeply( main->baz(), { name => 'baz', class => 'Test::SubExporter::GroupGen', group => 'symbolic', arg => { xyz => 2 }, collection => { col1 => { value => 2 } }, }, "parent class's generated baz does what we expect", ); is_deeply( main->subclass_baz(), { name => 'baz-sc', class => 'Test::SubExporter::GroupGenSubclass', group => 'symbolic', arg => { xyz => 4 }, collection => { col1 => { value => 3 } }, }, "inheriting class's generated baz does what we expect", ); t/group-generator.t000064400000007276152527414730010342 0ustar00#!/usr/bin/perl -T use strict; use warnings; =head1 TEST PURPOSE These tests check export group expansion, specifically the expansion of groups that use group generators. =cut # XXX: The framework is stolen from expand-group. I guess it should be # factored out. Whatever. -- rjbs, 2006-03-12 use Test::More tests => 12; BEGIN { use_ok('Sub::Exporter'); } my $alfa = sub { 'alfa' }; my $bravo = sub { 'bravo' }; my $returner = sub { my ($class, $group, $arg, $collection) = @_; my %given = ( class => $class, group => $group, arg => $arg, collection => $collection, ); return { foo => sub { return { name => 'foo', %given }; }, bar => sub { return { name => 'bar', %given }; }, }; }; my $config = { exports => [ ], groups => { alphabet => sub { { A => $alfa, b => $bravo } }, broken => sub { [ qw(this is broken because it is not a hashref) ] }, generated => $returner, nested => [qw( :generated )], }, collectors => [ 'col1' ], }; my @single_tests = ( # [ comment, \@group, \@output ] # [ "simple group 1", [ ':A' => undef ] => [ [ a => undef ] ] ], [ "simple group generator", [ -alphabet => undef ], [ [ A => $alfa ], [ b => $bravo ] ], ], [ "simple group generator with prefix", [ -alphabet => { -prefix => 'prefix_' } ], [ [ prefix_A => $alfa ], [ prefix_b => $bravo ] ], ], ); for my $test (@single_tests) { my ($label, $given, $expected) = @$test; my @got = Sub::Exporter::_expand_group( 'Class', $config, $given, {}, ); is_deeply( [ sort { lc $a->[0] cmp lc $b->[0] } @got ], $expected, "expand_group: $label", ); } for my $test (@single_tests) { my ($label, $given, $expected) = @$test; my $got = Sub::Exporter::_expand_groups( 'Class', $config, [ $given ], ); is_deeply( [ sort { lc $a->[0] cmp lc $b->[0] } @$got ], $expected, "expand_groups: $label [single test]", ); } my @multi_tests = ( # [ $comment, \@groups, \@output ] ); for my $test (@multi_tests) { my ($label, $given, $expected) = @$test; my $got = Sub::Exporter::_expand_groups( 'Class', $config, $given, ); is_deeply($got, $expected, "expand_groups: $label"); } ## eval { Sub::Exporter::_expand_groups('Class', $config, [[ -broken => undef ]]) }; like($@, qr/did not return a hash/, "exception on non-hashref groupgen return", ); ## { my $got = Sub::Exporter::_expand_groups( 'Class', $config, [ [ -alphabet => undef ] ], {}, ); my %code = map { $_->[0] => $_->[1] } @$got; my $a = $code{A}; my $b = $code{b}; is($a->(), 'alfa', "generated 'a' sub does what we think"); is($b->(), 'bravo', "generated 'b' sub does what we think"); } { my $got = Sub::Exporter::_expand_groups( 'Class', $config, [ [ -generated => { xyz => 1 } ] ], { col1 => { value => 2 } }, ); my %code = map { $_->[0] => $_->[1] } @$got; for (qw(foo bar)) { is_deeply( $code{$_}->(), { name => $_, class => 'Class', group => 'generated', arg => { xyz => 1 }, collection => { col1 => { value => 2 } }, }, "generated foo does what we expect", ); } } { my $got = Sub::Exporter::_expand_groups( 'Class', $config, [ [ -nested => { xyz => 1 } ] ], { col1 => { value => 2 } }, ); my %code = map { $_->[0] => $_->[1] } @$got; for (qw(foo bar)) { is_deeply( $code{$_}->(), { name => $_, class => 'Class', group => 'generated', arg => { xyz => 1 }, collection => { col1 => { value => 2 } }, }, "generated foo (via nested group) does what we expect", ); } } t/util-like.t000064400000006040152527414730007105 0ustar00#!/usr/bin/perl -T use strict; use warnings; use Test::More tests => 11; BEGIN { use_ok("Sub::Exporter"); } use lib 't/lib'; use Test::SubExporter::Faux; my ($generator, $installer, $reset, $exports); BEGIN { ($generator, $installer, $reset, $exports) = faux_installer; } my %generator; BEGIN { %generator = ( foo => sub { sub { 1 } }, bar => sub { sub { 2 } }, baz => sub { sub { 3 } }, BAR => sub { sub { 4 } }, xyzzy => sub { sub { 5 } }, ); } BEGIN { isa_ok($installer, 'CODE'); package Thing; BEGIN { main::use_ok('Sub::Exporter::Util', 'like'); } use Sub::Exporter -setup => { installer => $installer, generator => $generator, collectors => { -like => like }, exports => \%generator, }; } package main; my $code = sub { $reset->(); Thing->import(@_); }; $code->(qw(foo xyzzy)); exports_ok( $exports, [ [ foo => {} ], [ xyzzy => {} ] ], "the basics work normally" ); $code->(-like => qr/^b/i); exports_ok( $exports, [ [ BAR => {} ], [ baz => {} ], [ bar => {} ] ], "give me everything starting with b or B (qr//)" ); $code->(-like => [ qr/^b/i ]); exports_ok( $exports, [ [ BAR => {} ], [ baz => {} ], [ bar => {} ] ], "give me everything starting with b or B ([qr//])" ); $code->(-like => [ qr/^b/i => undef ]); exports_ok( $exports, [ [ BAR => {} ], [ baz => {} ], [ bar => {} ] ], "give me everything starting with b or B ([qr//=>undef])" ); # XXX: must use verbose exporter my %col = ( -like => [ qr/^b/i => { -prefix => 'like_' }, qr/zz/i => { -suffix => '_y2' }, ]); $code->(%col); everything_ok( $exports, [ [ BAR => { class => 'Thing', generator => $generator{BAR}, name => 'BAR', arg => {}, collection => \%col, as => 'like_BAR', into => 'main', }, ], [ bar => { class => 'Thing', generator => $generator{bar}, name => 'bar', arg => {}, collection => \%col, as => 'like_bar', into => 'main', }, ], [ baz => { class => 'Thing', generator => $generator{baz}, name => 'baz', arg => {}, collection => \%col, as => 'like_baz', into => 'main', }, ], [ xyzzy => { class => 'Thing', generator => $generator{xyzzy}, name => 'xyzzy', arg => {}, collection => \%col, as => 'xyzzy_y2', into => 'main', }, ], ], 'give me everything starting with b or B as like_$_ ([qr//=>{...}])' ); { my $like = Sub::Exporter::Util::like(); is(ref($like), 'CODE', 'like() gives us a generator'); eval { $like->() }; like($@, qr/no regex supplied/, "exception with no args to like->()"); eval { $like->([ "fake*reg{3}exp" => { a => 1 } ]) }; like($@, qr/not a regex/i, "exception with non qr// pattern in like"); } Changes000064400000011750152527414730006055 0ustar00Revision history for Sub-Exporter 0.987 2013-10-18 11:10:03 America/New_York update bugtracker metadata 0.986 2013-06-14 18:45:45 America/New_York typo fixes in docs (thanks, David Steinbrunner!) 0.985 2013-02-20 19:02:30 America/New_York documentation fixes (thanks, George Hartzell) 0.984 2012-06-05 07:59:40 America/New_York documentation fixes (thanks, GitHub user "everybody") 0.983 2011-01-24 documentation fixes (thanks, Karen Etheridge and Luc St-Louis!) 0.982 2009-01-16 add metadata for repo 0.981 2008-10-24 finally fix very occasional hash ordering issue in tests fix typo in SYNOPSIS (thanks, Florian!) 0.980 2008-09-14 fix inadvertant futzing with group generator args https://rt.cpan.org/Ticket/Display.html?id=38885 thanks, trendele! 0.979 2008-04-29 add INIT collector declare reservation of all CAPS collectors clarify documentation of -setup after report by GAISSMAI 0.978 2007-11-19 improve documentation of new installer/generator options deprecate calling "installer" the "exporter" WARNING: "exporter" OPTION WILL BE REMOVED AFTER 2008-06-01 major refactoring of the core generation/installation code tentative interface documentation for replacing it! 0.976 2007-08-30 fixed merge_col, which was not updated to work with \name generators collector hooks can now alter @_ to replace the value to be collected clarify args passed to generator in Tutorial; thanks MARKSTOS added commented-out name_map to Sub::Exporter::Util; future feature? 0.975 2007-07-04 update Tutorial to show (preferred) \'name' style for generators changed "standard" name of curry_class to curry_method added curry_chain added Sub::Exporter::Cookbook 0.974 2007-04-22 fix a bug: would try to export routines that didn't exist in the exporting package; this caused Sub::Install to give the unhelpful message "argument 'code' is not optional" 0.973 2007-02-02 document changes made in 0.972 minor code changes for readability 0.972 2006-12-05 allow exporter config to provide name (via string ref) of generator for groups and exports similarly allow a string ref for a method name for a collector hook remove some pointless conditions 0.971 2006-11-06 minor documentation clarification add Perl::Critic tests (disabled by default) 0.970 2006-06-27 defaults populate before collectors collect, now default group's value is undef by default, not 1 mixin_exporter can now export into objects, creating virtual classes 0.966 2006-06-17 correct documentation of collector hook args simplify internal use of setup_exporter clean up documentation in ::Util 0.965 2006-06-05 curry_class now allows the export to curry a differently-named method 0.961 2006-06-05 Data::OptList is now in its own dist; updated to use it 0.960 2006-05-31 added into and into_config to config 100% test coverage... almost! fix bug that prevented validation of opt lists with must_be=class 0.954 2006-05-11 tweaks to Data::OptList, moving toward its own dist: now it exports expand_opt_list is now opt_list_as_hash 0.953 2006-05-10 require Params::Util for craftier opt list validation use reinstall, rather than install, to avoid warnings on redef 0.952 2006-04-30 add missing file to manifest 0.951 2006-04-30 fix util-mixin.t to skip if prereqs are missing various changes to improve blessed/weird generators (thanks to Yuval Kogman for pointing problems out) 0.95 2006-04-26 break out Data::OptList for future disting remove an "optimization" that broke expand_opt_list improve detection of group generators improve data passed to hooks (if you relied on the guts, you'll break) the ::Util module 0.93 2006-03-26 internal refactoring add more arguments to collector hook calls 0.92 2006-03-16 FIX BUG in nested imports: when importing groups A and B, and group B includes group A, the nested group would be ignored, even though it was not recursing allow 'into_level' parameter to setup_exporter rewrite collection collector to be more efficient rewrite opt list handlers to be more efficient restate some code to improve clarity and coverage (now 100%) better diagnostic messages 0.91 2006-03-16 added "import elsewhere" option to generated exporter (thanks chansen!) 0.90 2006-03-11 first public release