Exporter-Renaming-1.19/000755 000765 000024 00000000000 11364415651 015116 5ustar00annostaff000000 000000 Exporter-Renaming-1.19/Changes000644 000765 000024 00000001410 11364413511 016376 0ustar00annostaff000000 000000 Revision history for Perl extension Exporter::Renaming. 0.01 Fri Sep 5 20:50:30 2003 - original version; created by h2xs 1.22 with options -AX -n Exporter::Renaming 1.16 Mon Sep 8 19:36:57 CEST 2003 - first release 1.17 Sun Jul 13 23:59:30 CEST 2008 - fixed bug in test file t/1.t 1.18 Mon Jul 14 17:03:09 CEST 2008 - A perl buglet (if new Exporter runs with old Carp) leads to two failed tests. fixed, released 1.19 Fr 23 Apr 2010 23:54:37 CEST - [rt.cpan.org #56367] renaming on export_to_import() too fixed by also overriding export_to_level - [rt.cpan.org #56368] modules capturing import vs "no Exporter::Renaming" fixed by adding a dedicated variable $renaming_on Exporter-Renaming-1.19/lib/000755 000765 000024 00000000000 11364415651 015664 5ustar00annostaff000000 000000 Exporter-Renaming-1.19/Makefile.PL000644 000765 000024 00000001007 11364367340 017067 0ustar00annostaff000000 000000 use 5.008; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Exporter::Renaming', 'VERSION_FROM' => 'lib/Exporter/Renaming.pm', # finds $VERSION 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1 ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'lib/Exporter/Renaming.pm', # retrieve abstract from module AUTHOR => 'Anno Siegel') : ()), ); Exporter-Renaming-1.19/MANIFEST000644 000765 000024 00000000222 11364366701 016244 0ustar00annostaff000000 000000 Changes Makefile.PL MANIFEST README lib/Exporter/Renaming.pm t/1.t META.yml Module meta-data (added by MakeMaker) Exporter-Renaming-1.19/META.yml000644 000765 000024 00000001013 11364415651 016362 0ustar00annostaff000000 000000 --- #YAML:1.0 name: Exporter-Renaming version: 1.19 abstract: Allow renaming of symbols on import author: - Anno Siegel license: unknown distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: {} no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.56 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 Exporter-Renaming-1.19/README000644 000765 000024 00000016552 11036476105 016004 0ustar00annostaff000000 000000 NAME Exporter::Renaming - Allow renaming of symbols on import SYNOPSIS # Enable renaming in Exporter use Exporter::Renaming; # Import File::Find::find as main::search use File::Find Renaming => [ find => search]; # Disable renaming no Exporter::Renaming ABSTRACT Allow Renaming of symbols on Import DESCRIPTION Overview This module adds the ability to rename symbols to the standard Exporter module. After "use Exporter::Renaming", you can import symbols from exporting modules not only under their original names, but also under names of your choosing. Here, *symbol* is used to mean anything that could be exported by a Module, that is, a Perl function or variable. Thus a symbol begins with an optional *type character* (one of "$", "@", "%", "&", and "*"), followed by a name (a Perl identifier, made up of alphanumerics and "_", starting with a non-digit). To trigger renaming behavior, the import list of a subsequent "use " statement must begin with the keyword 'Renaming', followed by a list reference, the , which describes the renaming imports (see below). After that, a normal import list may follow, which Exporter processes as usual. Renaming List The renaming list contains *renaming pairs*, which are pairs of symbols. The first part of a pair is the original symbol (as known to the exporting module) and the second one is the renamed symbol (as you want to use it after import). It is an error (fatal, as all "Renaming" or "Exporter" errors) if the renaming list has an odd number of elements, or if one of its symbols is invalid. If none of the symbols in a *renaming pair* contains a *type character*, an "&" is assumed. If only one has a *type character*, this type is assumed for the other one too. If both have type characters, it is an error if they don't agree. If the renamed symbol (the second part) of a *renaming pair* is undefined, the original symbol is imported unchanged, so you can include normal imports in a renaming list without retyping the name. It is an error for a symbol to appear more than once as the second part of a *renaming pair*, that is, to specify the same thing twice as the target of a renaming operation. It is allowed to import the same symbol multiple times with different targets. Maybe it even makes sense in some situations. Operation Exporter continues to behave normally for normal imports while renaming behavior is switched on. Only the presence of the keyword "Renaming", followed by an array reference in the first and second positions after a "use" statement triggers renaming. The renaming behavior of Exporter is thus compatible with its standard behavior. If renaming must be switched off for some reason, this can be done via "no Export::Renaming". If an *import list* contains both a renaming list and a sequence of normal import statements, the renaming is done first, as indicated by its position. No cross-check is done between the results of renaming and the normal imports, as if these resulted from two separate "use" statements. EXAMPLES All examples assume that use Exporter::Renaming; has been called (and that "no Exporter::Renaming" hasn't). The most obvious application of "Exporter::Renaming" is to solve a name conflict. Suppose our module already defines a function "find", and we want to use the standard "File::Find" module. We could then rename "find" from "File::Find" to "search" in our own module: use File::Find Renaming => [ find => 'search' ]; Let's assume the "finddepth" function from File::Find doesn't cause a name conflict, and we want to import it under its original name as well. This does it in the renaming list: use File::Find Renaming => [ find => 'search', finddepth => undef, ]; ...as does this, but explicitly: use File::Find Renaming => [ find => 'search', finddepth => 'finddepth', ]; ...while this uses a regular import: use File::Find Renaming => [ find => 'search' ], 'finddepth'; Should you find it annoying that a pedantic module author has chosen to adorn all of the module's exports with a redundant prefix (these things happen), you could do this: use Mythical::Graphics::Module Renaming => [ gfxColor => '%color', # this imports a hash gfxPen => 'pen', gfxLine => 'line', # .... # etc ]; ...lower-casing the names as well. If you need to add clarifying prefixes that a sloppy module author has neglected to provide in the exports (these things happen), you go the other way around: use Legendary::Graphics::Module Renaming [ Color => '%gfxColor', Pen => 'gfxPen', Line => 'gfxLine', # ... # etc ]; ...also lower-casing the initial letters. If you are confronted with a standard module that uses a slightly non-standard naming convention (it happens), you can rectify the situation: use Data::Dumper Renaming => [ Dumper => 'dump' ]; Now you can say "print dump \ %some_hash" instead of "print Dumper ..."; CAVEATS * As has been mentioned in section Operation, no cross-check is done between renaming exports and normal exports that go on in the same "use" statement. This means that a renaming import may later be overwritten by a normal import without a clear indication. This happens when one of the new names given in renaming coincides with one of the original ones imported through normal import. * "Exporter::Renaming" only affects modules that do standard exporting, that is, modules that inherit their "import" method from Exporter. Modules that use a different "import" method are unaffected and don't understand renaming lists. * Renaming doesn't affect the name c sees for a function. This should come as no surprise, since normal export doesn't affect this name either. It is always the (package-qualified) name the function was originally compiled with. BUGS * The lack of a cross-check between renaming and normal imports is regrettable, but unlikely to be fixed unless Renaming is made part of Exporter. Except for the simplest cases, only Exporter can parse an export list. * Calls of "use Exporter::Renaming" and "no Exporter::Renaming" don't nest. Instead of switching unconditionally, "no Renaming" should only switch off the behavior if it was off in the corresponding call to "use Exporter::Renaming". A future release may address this. SEE ALSO Exporter, Perl AUTHOR Anno Siegel, ACKNOWLEDGEMENTS Thanks to Avi Finkel (avi@finkel.org) and Simon Cozens (simon@simon-cozens.org) for a discussion of this project on IRC. While brief, their remarks helped me think about things the right way. COPYRIGHT AND LICENSE Copyright 2003 by Anno Siegel This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Exporter-Renaming-1.19/t/000755 000765 000024 00000000000 11364415651 015361 5ustar00annostaff000000 000000 Exporter-Renaming-1.19/t/1.t000644 000765 000024 00000013266 11364411543 015712 0ustar00annostaff000000 000000 #!perl # We use "require()" and "->import" in these tests to emulate # "use" at run-time # work around perl buglet: if new Exporter is used with old Carp # Carp attributes errors wrongly BEGIN { $Carp::Internal{Exporter}++; $Carp::Internal{'Exporter::Heavy'}++; } use Test::More; my $n_tests; ### Function of Exporter::Renaming::import (and unimport) {{ # '{{' means block isn't indented require Exporter; my $ex_im = \ &Exporter::import; use_ok('Exporter::Renaming'); my $new_im = \ &Exporter::import; ok( $ex_im != $new_im, 'Exporter::import changed'); Exporter::Renaming->import; ok( $new_im == \ &Exporter::import, 'Exporter::import unchanged'); Exporter::Renaming->unimport; # equiv to no Exporter::Renaming ok( $ex_im == \ &Exporter::import, 'Exporter::import reset'); Exporter::Renaming->import; # leave switched on for subsequent tests ok( $new_im == \ &Exporter::import, 'Exporter::import changed again'); BEGIN { $n_tests += 5 } }} ### Basic renaming (excecised with standard module File::Find) # File::Find does secondary imports, so this is summarily tested here # as well {{ require File::Find; eval { # catch import dying (first time only) File::Find->import( Renaming => [ find => 'search']); }; like( $@, qr/^$/, 'import successful'); ok( \ &search == \ &File::Find::find, 'find renamed to search'); undef *search; die unless defined &File::Find::find; # Combine with standard import File::Find->import( Renaming => [ find => 'search'], 'finddepth'); ok( \ &finddepth == \ &File::Find::finddepth, 'finddepth imported'); ok( \ &search == \ &File::Find::find, 'find renamed to search'); undef *search; undef *finddepth; # multiple import File::Find->import( Renaming => [ find => 'woohoo', find => 'weehee']); ok( \ &woohoo == \ &File::Find::find, 'find renamed to woohoo'); ok( \ &weehee == \ &File::Find::find, 'find renamed to weehee'); undef *woohoo; undef *weehee; # import under original name as default File::Find->import( Renaming => [ find => undef]); ok( \ &find == \ &File::Find::find, 'find not renamed'); # [rt.cpan.org #56367] renaming on export_to_import() too # (2010-04-23) # must also override export_to_level(). (used by Benchmark) use Benchmark (); eval { Benchmark->import(Renaming => [ timethis => 'howfast' ], 'cmpthese') }; ok(!length $@, 'export_to_level survived'); ok(\ &Benchmark::timethis == \ &howfast, "Benchmark::timethis renamed to howfast"); ok(\ &Benchmark::cmpthese == \ &cmpthese, "Benchmark::cmpthese imported"); # [rt.cpan.org #56368] modules capturing import vs "no Exporter::Renaming" # example uses the Roman module, skip if not present Exporter::Renaming->import; # make sure we're active my $have_roman = eval { require Roman }; SKIP: { skip 'needs Roman module', 1 unless $have_roman; Exporter::Renaming->unimport; eval { Roman->import('Roman') }; ok(!length $@, 'Roman unhurt'); Exporter::Renaming->import; # switch back on } BEGIN { $n_tests += 11 } }} ### Handling Exporter errors {{ # normal import of non-existent symbol my $error_line = __LINE__ + 2; eval { File::Find->import( 'gibsnich'); }; like( $@, qr/line $error_line/, 'direct Exporter error message'); # renaming non-existent symbol $error_line = __LINE__ + 2; eval { File::Find->import( Renaming => [ gibsnich => 'wirdnix'] ); }; like( $@, qr/line $error_line/, 'indirect Exporter error message'); BEGIN { $n_tests += 2 } }} ### own error handling {{ # odd number of renaming elements my $error_line = __LINE__ + 1; # check location once eval { File::Find->import( Renaming => [ 'xxx', 'yyy', 'zzz']) }; like( $@, qr/line $error_line/, 'error location'); like( $@, qr/odd number/i, 'odd number'); # invalid type char eval { File::Find->import( Renaming => [ '+xxx' => 'yyy']) }; like( $@, qr/invalid type/i, 'invalid type old'); eval { File::Find->import( Renaming => [ 'xxx' => '+yyy']) }; like( $@, qr/invalid type/i, 'invalid type new'); # different type chars eval { File::Find->import( Renaming => [ '%xxx' => '$yyy']) }; like( $@, qr/different types/i, 'different types'); # invalid name eval { File::Find->import( Renaming => [ 'xxx' => 'yy y']) }; like( $@, qr/invalid name/i, 'invalid name'); # multiple renamings eval { File::Find->import( Renaming => [ 'xxx' => 'yyy', 'zzz' => 'yyy']) }; like( $@, qr/multiple renamings/i, 'multiple renamings'); BEGIN { $n_tests += 7 } }} ### For the following tests we want a pseudo-module that exports # all types of symbols. We call it SampleMod. BEGIN { package SampleMod; require Exporter; our @ISA = qw( Exporter); our @EXPORT_OK = qw( code $scalar @array %hash *glob); sub code { 123 } our $scalar = 123; our @array = ( 123, 456); our %hash = ( 123 => 456); sub glob { 456 } our $glob = 456; our @glob = ( 456, 789); our %glob = ( 456 => 789); } ### full functional test (check all types) {{ our ($scalar, @array, %hash, $glob, @glob, %glob); SampleMod->import( Renaming => [ code => 'code', scalar => '$scalar', array => '@array', hash => '%hash', glob => '*glob', ]); is( code(), 123, 'code'); is( $scalar, 123, 'scalar'); is( "@array", '123 456', 'array'); is( $hash{ 123}, 456, 'hash'); is( $glob, 456, 'glob/scalar'); is( "@glob", '456 789', 'glob/array'); is( $glob{ 456}, 789, 'glob/hash'); BEGIN { $n_tests += 7 } }} ### handling of type-character {{ # dollar right undef *scalar; SampleMod->import( Renaming => [ 'scalar' => '$scalar']); is( $scalar, 123, 'dollar right'); # dollar left undef *scalar; SampleMod->import( Renaming => [ '$scalar' => 'scalar']); is( $scalar, 123, 'dollar left'); # two dollars undef *scalar; SampleMod->import( Renaming => [ '$scalar' => '$scalar']); is( $scalar, 123, 'two dollars'); BEGIN { $n_tests += 3 } }} BEGIN { plan tests => $n_tests } Exporter-Renaming-1.19/lib/Exporter/000755 000765 000024 00000000000 11364415651 017474 5ustar00annostaff000000 000000 Exporter-Renaming-1.19/lib/Exporter/Renaming.pm000644 000765 000024 00000030013 11364413613 021563 0ustar00annostaff000000 000000 package Exporter::Renaming; use 5.008; use strict; use warnings; use Carp; our $VERSION = 1.19; my $renaming_on; # are we active? my $exporter_import; # holds coderef to original Exporter behavior, if defined my $exporter_to_level; # same for Export::Heavy::heavy_export_to_level # switch on renaming behavior of Exporter sub import { return if $renaming_on; # never do this twice require Exporter; require Exporter::Heavy; $exporter_import = \ &Exporter::import; # alias for original $exporter_to_level = \ &Exporter::Heavy::heavy_export_to_level; no warnings 'redefine'; *Exporter::import = \ &renaming_import; # renaming behavior *Exporter::Heavy::heavy_export_to_level = \ &renaming_to_level; $renaming_on = 1; } # restore Exporter's original behavior sub unimport { return unless $renaming_on; no warnings 'redefine'; *Exporter::import = $exporter_import; # normal behavior *Exporter::Heavy::heavy_export_to_level = $exporter_to_level; $renaming_on = 0; # allow import again } # This is the import routine we supplant into Exporter. It interprets # a renaming package, if any, then resumes normal import through # "goto &$exporter_import". This is this sub's way of returning sub renaming_import { # be as inconspicious as possible goto $exporter_import unless $renaming_on; my ($from_module, $key, $renamings, @normal) = @_; # check if we are needed at all goto $exporter_import unless $key and $key eq 'Renaming' and ref $renamings eq 'ARRAY'; my $to_module = caller; process_renaming($from_module, $to_module, $renamings); # do any remaining straight imports return unless @normal; @_ = ($from_module, @normal); goto $exporter_import; } # replacement for Exporter::Heavy::heavy_export_to_level sub renaming_to_level { goto $exporter_to_level unless $renaming_on; my $pkg = shift; my $level = shift; (undef) = shift; # XXX redundant arg my $callpkg = caller($level); my ($key, $renamings, @normal) = @_; return $pkg->export($callpkg, @_) unless $key and $key eq 'Renaming' and ref $renamings eq 'ARRAY'; process_renaming($pkg, $callpkg, $renamings); $pkg->export($callpkg, @normal) if @normal; } sub process_renaming { my ($from, $to, $renamings) = @_; my %table; # build renaming table, basically as %table = reverse @$renamings, # but do error checking and type (sigil) propagation croak( "Odd number of renaming elements") if @$renamings % 2; while ( @$renamings ) { my ( $old_sym, $new_sym) = ( shift @$renamings, shift @$renamings); $new_sym ||= $old_sym; # default to straight import my ( $old_type, $old_name) = _get_type( $old_sym); my ( $new_type, $new_name) = _get_type( $new_sym); # check type and name croak( "Invalid type character in '$old_sym'") unless defined $old_type; croak( "Invalid type character in '$new_sym'") unless defined $new_type; # Check if $new_name is valid ($old_name will be checked by # standard Exporter) croak( "Invalid name in '$new_sym'") unless $new_name =~ /^[A-Za-z_]\w*$/; # type propagation my $type = $old_type || $new_type || '&'; $old_type ||= $type; $new_type ||= $type; croak( "Different types: old '$old_sym', new '$new_sym'") if $old_type ne $new_type; $new_sym = "$type$new_name"; $old_sym = "$type$old_name"; # Check table for multiple entries croak( "Multiple renamings to '$new_sym'") if exists $table{ $new_sym}; $table{ $new_sym} = $old_sym; } # Jump through Exporter's hoops for all original symbols { package Exporter::Renaming::Inter; # name space for importing # We want Exporter's messages passed on to our user our @CARP_NOT = qw(Exporter Exporter::Renaming); # "values %table" may list some symbols more than once, but Exporter # sorts that out. $exporter_import->($from, values %table); # original names } # If we are here, all imports are ok (under the original names) # now alias symbols into user space according to table while ( my ( $new, $old) = each %table ) { ( my( $type), $new) = _get_type( $new); ( undef, $old) = _get_type( $old); _sym_alias( $type, "${from}::$old", "${to}::$new"); } } # split off type character sub _get_type { local $_ = shift; my ( $type, $name) = /(\W?)(.*)/; return if $type and $type !~ /[\$@%&*]/; # reject invalid type chars ( $type, $name); } # create alias of any type (the only substantial copy of code from Exporter) sub _sym_alias { my ( $type, $old, $new) = @_; $type ||= '&'; no strict 'refs'; *{$new} = $type eq '$' ? \ ${ $old} : $type eq '@' ? \ @{ $old} : $type eq '%' ? \ %{ $old} : $type eq '&' ? \ &{ $old} : $type eq '*' ? \ *{ $old} : undef; ; } 1; __END__ =head1 NAME Exporter::Renaming - Allow renaming of symbols on import =head1 SYNOPSIS # Enable renaming in Exporter use Exporter::Renaming; # Import File::Find::find as main::search use File::Find Renaming => [ find => search]; # Disable renaming no Exporter::Renaming =head1 ABSTRACT Allow Renaming of symbols on Import =head1 DESCRIPTION =head2 Overview This module adds the ability to rename symbols to the standard Exporter module. After C, you can import symbols from exporting modules not only under their original names, but also under names of your choosing. Here, I is used to mean anything that could be exported by a Module, that is, a Perl function or variable. Thus a symbol begins with an optional I (one of C<$>, C<@>, C<%>, C<&>, and C<*>), followed by a name (a Perl identifier, made up of alphanumerics and C<_>, starting with a non-digit). To trigger renaming behavior, the import list of a subsequent CmoduleE> statement must begin with the keyword 'Renaming', followed by a list reference, the , which describes the renaming imports (see below). After that, a normal import list may follow, which Exporter processes as usual. =head2 Renaming List The renaming list contains I, which are pairs of symbols. The first part of a pair is the original symbol (as known to the exporting module) and the second one is the renamed symbol (as you want to use it after import). It is an error (fatal, as all C or C errors) if the renaming list has an odd number of elements, or if one of its symbols is invalid. If none of the symbols in a I contains a I, an C<&> is assumed. If only one has a I, this type is assumed for the other one too. If both have type characters, it is an error if they don't agree. If the renamed symbol (the second part) of a I is undefined, the original symbol is imported unchanged, so you can include normal imports in a renaming list without retyping the name. It is an error for a symbol to appear more than once as the second part of a I, that is, to specify the same thing twice as the target of a renaming operation. It is allowed to import the same symbol multiple times with different targets. Maybe it even makes sense in some situations. =head2 Operation Exporter continues to behave normally for normal imports while renaming behavior is switched on. Only the presence of the keyword C, followed by an array reference in the first and second positions after a C statement triggers renaming. The renaming behavior of Exporter is thus compatible with its standard behavior. If renaming must be switched off for some reason, this can be done via C. If an I contains both a renaming list and a sequence of normal import statements, the renaming is done first, as indicated by its position. No cross-check is done between the results of renaming and the normal imports, as if these resulted from two separate C statements. =head1 EXAMPLES All examples assume that use Exporter::Renaming; has been called (and that C hasn't). The most obvious application of C is to solve a name conflict. Suppose our module already defines a function C, and we want to use the standard C module. We could then rename C from C to C in our own module: use File::Find Renaming => [ find => 'search' ]; Let's assume the C function from File::Find doesn't cause a name conflict, and we want to import it under its original name as well. This does it in the renaming list: use File::Find Renaming => [ find => 'search', finddepth => undef, ]; ...as does this, but explicitly: use File::Find Renaming => [ find => 'search', finddepth => 'finddepth', ]; ...while this uses a regular import: use File::Find Renaming => [ find => 'search' ], 'finddepth'; Should you find it annoying that a pedantic module author has chosen to adorn all of the module's exports with a redundant prefix (these things happen), you could do this: use Mythical::Graphics::Module Renaming => [ gfxColor => '%color', # this imports a hash gfxPen => 'pen', gfxLine => 'line', # .... # etc ]; ...lower-casing the names as well. If you need to add clarifying prefixes that a sloppy module author has neglected to provide in the exports (these things happen), you go the other way around: use Legendary::Graphics::Module Renaming [ Color => '%gfxColor', Pen => 'gfxPen', Line => 'gfxLine', # ... # etc ]; ...also lower-casing the initial letters. If you are confronted with a standard module that uses a slightly non-standard naming convention (it happens), you can rectify the situation: use Data::Dumper Renaming => [ Dumper => 'dump' ]; Now you can say C instead of C; =head1 CAVEATS =over =item * As has been mentioned in section L, no cross-check is done between renaming exports and normal exports that go on in the same C statement. This means that a renaming import may later be overwritten by a normal import without a clear indication. This happens when one of the new names given in renaming coincides with one of the original ones imported through normal import. =item * C only affects modules that do standard exporting, that is, modules that inherit their C method from Exporter. Modules that use a different C method are unaffected and don't understand L. =item * Renaming doesn't affect the name c sees for a function. This should come as no surprise, since normal export doesn't affect this name either. It is always the (package-qualified) name the function was originally compiled with. =back =head1 BUGS =over =item * The lack of a cross-check between renaming and normal imports is regrettable, but unlikely to be fixed unless Renaming is made part of Exporter. Except for the simplest cases, only Exporter can parse an export list. =item * Calls of C and C don't nest. Instead of switching unconditionally, C should only switch off the behavior if it was off in the corresponding call to C. A future release may address this. =back =head1 SEE ALSO Exporter, Perl =head1 AUTHOR Anno Siegel, Esiegel@zrz.tu-berlin.deE =head1 ACKNOWLEDGEMENTS Thanks to Avi Finkel (avi@finkel.org) and Simon Cozens (simon@simon-cozens.org) for a discussion of this project on IRC. While brief, their remarks helped me think about things the right way. =head1 COPYRIGHT AND LICENSE Copyright 2003 by Anno Siegel This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut