NAME
Exporter::VA - Improved Exporter featuring Versioning and Aliasing.
AUTHOR
John M. Dlugosz
SYNOPSIS
In module ModuleName.pm:
package ModuleName;
use Exporter::VA qw/import AUTOLOAD VERSION/;
our %EXPORT= ( # all configuration done in this one hash
foo => [ v1.0, 'foo_old', v2.0, 'foo_new' ],
bar => 'bar_internal',
baz => 'baz',
fobble => \&figure_it_out, # parameter list is (caller, version, symbol, param-list tail)
bobble => \\&_boble_internal,
'$x' => '$x',
'$y' => \\$y, # a hard reference rather than a name
':tagname' => [ 'foo', 'bar' ],
':DEFAULT' => [ v1.0, ':_old_imports', v2.3, ':_new_imports' ],
':_old_imports' => [ 'foo', 'bar', 'baz', 'fobble' ],
':_new_imports' => [ 'fobble' ],
'.option' => "value",
'.default_VERSION' => v1.5,
'.warnings' => 1
);
In other files which wish to use ModuleName:
use ModuleName;
use ModuleName v2.1;
use ModuleName v2.1 qw/ foo bar fobble $y/;
DESCRIPTION
This main incentive in creating this exporter is to allow modules to be updated and get rid of default exports in newer releases, while still maintaining compatibility with older code.
What it Gives the Client's 'use' Statement
If ModuleName gets its import
function via Exporter::VA
, then the client that use
s ModuleName will generally see these features:
use ModuleName v2.3.4 qw( foo &bar $x -verbose :constants );
- names
-
List the names of the things you want imported. Functions may omit the
&
character. You can import&functions
,$scalars
,%hashes
,@arrays
, and even<FILES>
. -
A group of things may be named with a tag, beginning with a
:
character. Naming this will expand into the group it represents. - pragmas
-
An item may be listed which has some effect on the import process but doesn't actually import a symbol by that name. Ideally, these begin with a leading
-
(dash) character, but any symbol can actually be a pragma. Pragmas can take arguments.Different clients of a module can have different options in effect which influence the behavior of the module, and the module can, with the help of
Exporter::VA
, keep track of which client has which settings and react accordingly. For example, some clients may activate-verbose
mode, and others leave it off.Those that begin with a double-dash are handled by the
Exporter::VA
module itself, and are not defined by the module you areuse
-ing. So, their meaning and availability will be the same on any module that is built withExporter::VA
.These are
--verbose_import
, which will detail the import process for purposes of troubleshooting; and--dump
which will print the state of the%EXPORT
definition and internal state.
I said it will generally have these features because Exporter::VA
is very customizable. Modules with unique needs that had their own exporter code can hopefully "upgrade" to Exporter::VA
and get it to work like it did before, gaining the versioning ability.
A future version may support patterns as seen in the classic Exporter
module. Specifically, a parameter beginning with !
or /
would be handled internally, as would parameters that are qr's rather than strings.
Parameters beginning with +
will never be used specially by Exporter::VA
, so if you want to add a feature that uses a different prefix symbol, this is a good one to use.
Module Versioning
The syntax of the use
statement allows for a version number as an indirect object (that is, no comma follows it). A module may export different things depending on the requested version. Tags may expand into different lists based on version. Specifically (and this was the original motivation for writing this), the :DEFAULT
tag (equivilent to the @EXPORT
list in the classic Exporter module) may contain different things based on version.
How to Incorporate
The module that wishes to draw upon Exporter::VA
for its export needs can simply import the import
and VERSION
functions. Note that this is different from the classic Exporter module in that it needs use
instead of require
, and does not inherit from it.
You can import the import
function and Exporter::VA
will provide you with one. If you prefer, you can write import
yourself to do some enhancements, and then from it call one of the helper functions.
You can also import the AUTOLOAD
function, which is an easy way to lazy-generate any aliased functions that are called via module-qualified syntax. There are other ways to do this, described later.
All information for configuring the module's use of Exporter::VA
is given in a single hash. By default, this will be the %EXPORT
hash found in the calling package.
Or, you can include a hashref as a parameter to the use
, and this will specify the destination.
my %Export= ( #...
use Exporter::VA (\%Export, ':normal'); # look ma, no package globals!
use Exporter::VA ('import', {
foo => \\&internal_foo,
bar => \\&internal_bar
} ); # put it all inline in this statement.
However it's found, this document will call this information the %EXPORT
definition.
Keys in the %EXPORT definition
There are several kinds of keys that may be present in the %EXPORT
definition, and they have different purposes and different usage rules.
- symbols
-
If the hash key begins with a Perl sigil, left-angle (a pseudo-sigel for file handles) or a Perl identifier character (to be exact,
/^[$@%*&\w<]
) it names a symbol that the module's user may import by that name. If there is no sigil, then it assumes a&
, so you can sayfoo
instead of&foo
. -
If the hash key begins with a
:
character, then it names a list of other names. The module's user may use this tag to import the whole list, as with the traditionalExporter
module. - pragmas
-
If the hash key begins with a
-
(dash) character, then the module user may "import" it to trigger code or special features of the module. - options
-
If the hash key begins with a
.
(dot) character, it has special meaning toExporter::VA
and is used as an option or parameter to configure the module's use of the exporter.
symbols
If the hash key begins with a Perl sigil or a Perl identifier character (to be exact, /^[$@%*&\w<]
) it names a symbol that the module's user may import by that name.
The value may be a name, a hard link, a callback, or a version list.
- name
-
If the value is a scalar, then it is the name of the symbol within the package to export. This does not have to be the same as the export name that the module's user will see.
%EXPORT= ( '&foo' => "foo", # & is optional for functions '$bar' => '$_internal_bar', 'baz' => "" # means "same". );
As a special case, an empty string means that the internal name is the same as the export name.
foo => "foo"
can also be specified asfoo => ''
. See also the .plain option.A value of
undef
means that the symbol is not available for import. This is the same as not listing it at all for a simple name value, but is useful as part of a version list, to indicate that the function was dropped at some point.This name is matched against the defining package's symbol table. It does not handle inheritence or fancier things. If you need that, use a hard link or callback instead. There is no plan to support inherited methods, since (virtual) methods are commonly not exported anyway and it is trivial to work-around for the desired effect without bothering the module's client.
- non-scalars
-
If the value is not a scalar or
undef
, than it is a reference of some kind. This module distinguishes several types based on the kind of reference: array ref is a version list, code ref is a callback, scalar ref is a hard link. Others are errors. - version list
-
If the value is an array reference, then it specifies alternating v-strings and symbol values.
foo => [ v1.0, 'foo_old', v2.0, 'foo_new' ]
It must begin with a v-string that is the oldest supported version. That is followed by the value to use for that version and later, until it changed with the next named version, and so on. The last value is "current" and used up to and including this module's stated
$VERSION
.So, in the above example, if the module's user called for:
use ModuleName v1.78 ('foo'); # note no comma after v-string
then
ModuleName
will export itsfoo_old
function as the caller'sfoo
.The values in this list in the even positions are the same kinds of values used for symbol name entries, except for another version list. It may be a name, hard link, callback, or
undef
. - callbacks
-
If the value is a code reference, then it specifies a callback function. This code will be called when the symbol is being imported, and can do something more complex than the version list allows.
%EXPORT= ( '&foo' => \&figure_it_out_later, '$bar' => sub { ... logic goes here ... }, '%fible' => sub { \%internal_fible } );
When that line is triggered at import time, the code is called with the following parameters:
sub figure_it_out_later { my ($blessed_export_def, $caller, $version, $symbol, $param_list_tail)= @_;
The
$caller
is the package name of the module's user; that is, the one doing the importing.$version
is the v-string of the version he's asking for.$symbol
is the name of the symbol he's asking for (a function name will have the&
added). Finally, the last argument is an array ref of the rest of the parameter list toimport
, which this callback may inspect or modify (see pragmas, below).(More technically, the
$param_list_tail
will contain the rest of the items in the tag definition if triggered during a:TAG
import, or the rest of the "batch" if extension code triggers importing of a list of items programmatically.)To indicate success and that a symbol was found, function must return a reference to the proper type of thing, which is what will be placed in the caller's package.
To indicate success and that no symbol should be imported (that is, a pragmatic import) the function returns
undef
. The intent is for pragmatic imports to begin with a dash, but for compatibility with existing modules that may want to adoptExporter::VA
, any symbol may silently "fail" to import this way, without error.To indicate an error,
die
with an error string. - hard links
-
As explained above, if the
%EXPORT
definition contains a text string like'&foo' => "&foo"
, then when triggered it will symbolically reference&ModuleName::foo
. Instead, you can specify a hard-link, and not even have a name that is visible outside the package (or even the scope!).In the section on callbacks, the callback
'%fible' => sub { \%internal_fible }
ignores the parameters and always returns a reference to the same thing. This is exactly what is meant by a hard-link here. Only there is a shortcut for doing it:'%fible' => \\%internal_fible
Basically, use a double-reference to the desired symbol, and that will directly be used at export time as opposed to finding it by name first.
Syntactically, this is a reference to a scalar which must itself contain a reference to the right kind of thing. It is sensible for the normal meaning of the backslash in Perl, adding another layer of deferring things.
tags
If the hash key in the %EXPORT
definition begins with a :
character, then it names a list of other names. The module's user may use this tag to import the whole list, as with the traditional Exporter
module.
The value is a list ref. It may either be a list of names, or a list of alternating v-strings and tags.
A list of names is simply that. The contents of the list replace the tag's name in the import
parameter list. So, given
%EXPORT= (
apple => ...
banana => ...
pear => ...
potato => ...
cheeze => ...
':fruit' => [ qw/apple banana pear/ ]
);
Then the module's user might say
use ModuleName v1.78 qw/potato :fruit cheeze/;
to mean the exact same thing as
use ModuleName v1.78 qw/potato apple banana pear cheeze/;
The other form is used to version a list. The concept is the same as the version list used for symbol values: The list alternates v-strings and other tag names. The original tag is replaced by the one that matches the desired version, and then processing continues.
For example, given
%EXPORT= (
':list' => [ v1.0, ':_old_list', v2.3, ':_new_list' ],
':_old_list' => [ 'foo', 'bar', 'baz', 'fobble' ],
':_new_new' => [ 'fobble' ]
);
then
use ModuleName v1.2 ':list';
means the same thing as
use ModuleName ':_old_list';
and
use ModuleName v2.4 ':list';
means the same thing as
use ModuleName ':_new_list';
(except that directly importing something that begins with an underscore gives a warning).
the :DEFAULT tag
If there is nothing specified in the import parameter list, then it behaves as if :DEFAULT
was specified. This is how you list what gets imported if you don't specify otherwise, and is the equivilent of @EXPORT
in the traditional Exporter
module.
symbols and tags work together
If a package imports the default in this example, it will note that foo
was imported in versions before v2.3 but dropped as a default in that version. But, in version 2.0 the implementation changed, so it will pull in foo_old
if the requested version is less than 2, or foo_new
if between 2.0 and 2.3, or not import it at all if 2.3 or later.
%EXPORT= (
foo => [ v1.0, 'foo_old', v2.0, 'foo_new' ],
':DEFAULT' => [ v1.0, ':_old_imports', v2.3, ':_new_imports' ],
':_old_imports' => [ 'foo', 'bar', 'baz', 'fobble' ],
':_new_imports' => [ 'fobble' ],
# ... others ...
Looking at it step-by step, the module changed what was imported by default. In the traditional system, that's like changing @EXPORT
and moving them to @EXPORT_OK
instead.
Meanwhile, the implementation of foo
changed in version 2.0. The decision of which version of foo
to import is independant and orthogonal of the decision of whether foo
gets imported by default.
pragmas
If the hash key in the %EXPORT
definition begins with a -
(dash) character, then it defines a pragmatic import. Also, unlike other "symbol" names, since this is not going to define a Perl symbol, it is not limited to legal identifier names. Any character that does not otherwise cause problems may be used in an option that begins with a dash.
This is used to trigger a callback, without actually importing anything. For example, given
%EXPORT= (
'-prag' => \&callme,
# ...
then the calling module can say:
use ModuleName v1.0 qw/ foo -prag bar/;
and between doing the work of resolving foo
and resolving bar
, it will trigger the function &callme
. This is exactly like a callback for a symbol, except that if the symbol name begins with a dash it is thrown away after it resolves it, and doesn't put it into the calling module's package. (Note that "resolving" here means figuring out what to import and adding it to a worklist. It doesn't actually modify the caller's namespace until later.)
Since a callback can see the rest of the import parameter list and modify it, a pragma can take parameters by shifting them off the list.
A pragma might be used to customize the behavior of a module. The module can remember the settings associated with each importer by using a hash keyed by the caller (importer).
%EXPORT= (
'-strict' => sub { my $caller= shift; $strict{$caller}=1; }
options
If the hash key in the %EXPORT
definition begins with a .
(dot) character, it has special meaning to Exporter::VA
and is used as an option or parameter to configure the module's use of the exporter.
Those that begin with a &
symbol (after the initial dot) take code references that are invoked just like export callbacks.
- .allowed_VERSIONS
-
The version asked for must be on this list. Normally, version numbers are checked to see if they are between version numbers where things changed, but the exact number doesn't matter. If you specify a list here, then only versions on this list are accepted.
'.allowed_VERSIONS' => [ v1.0, # initial relase v1.1, # minor fixes
- .&begin
-
This is called just like a symbol callback, before proceeding with processing all the symbols in the import list. Any return value is ignored.
%EXPORT= ( '.&begin' => sub { my ($blessed_export_def, $caller, $version, '.&begin', $param_list_tail)= @_; #...
- .check_user_option
-
'.&check_user_option' => &checkfunction
This can be used to supply a checking function without having to derive a class. It works exactly like the
check_user_option
method.If you have callbacks that respond to user-defined options, but did not have to derive a class from
Exporter::VA
to do what you needed, then use this to implement warning-checking on those options. - .default_VERSION
-
If the module importer does not specify a version in its
use
statement, then this value is used. Typically, when switching fromExporter
toExporter::VA
to facilitate reducing the list of things exported by default, or versioning a symbol, set the.default_VERSION
to the last version before the change. Then, any code that doesn't specify otherwise will get the backward-compatible imports.'.default_VERSION' => v1.99, # changed stuff with 2.0, must ask for new stuff.
If not specified, then a v-string is required in the
use
statement. - .&end
-
Just like
.&begin
, but called after theimport
list has been all processed, and the symbol parameter of course is'.&end'
to match.Note that you may examine and alter the worklist at this time.
- .plain
-
This is a list ref that contains symbol names. Before processing begins, everything on it is added to the
%EXPORT
definition as self-named symbols without versioning or aliases. This makes it easy to have something like the traditional@EXPORT
list, copying such a list when upgrading to useExporter::VA
without reformatting it, or just being more succinct.For example,
%EXPORT= ( '.plain' => [qw/foo $x &zed/],
will generate (recall that an empty string means "same name as the key")
%EXPORT= ( '&foo' => "", '$x' => "", '&zed' => "",
You can also list a
:tag
name here, and this will expand to the tag names. The tag must be a list of names, not an alternating v-string/name list.This is similar to the traditional
Exporter::export_tags
andExporter::export_ok_tags
, in that it it prevents you from having to invidually list as exports all the items that are also in the tag's definition list.%EXPORT= ( '.plain' => [qw/:DEFAULT fozzle/], ':DEFAULT' => [qw/foo bar baz/], bar => '_bar_internal' );
The above example will add plain export entries for
foo
andbaz
as well asfozzle
, but silently ignorebar
as redundant since it is already listed as an export. - .&unknown_feature
-
%EXPORT= ( '.&unknown_feature' => sub { my ($blessed_export_def, $caller, $version, $weird_parameter, $param_list_tail)= @_; #...
Before generating an error for an
import
parameter that is syntactically incorrect, this callback will be tried.If it returns, then the module assumes that this callback handled the whatever-it-was. If the callback cannot handle the parameter, it should fail by calling
die
.The callback can do its work by manipulating the object and the caller's namespace, and calling the supplied implementation functions such as
export
.For example,
use ModuleName 1.0 qw/foo -prag +huh bar/;
will trigger
.&unknown_feature
when the"+huh"
parameter is reached during processing. You can use this to implement the classicExporter
's feature of having a leading!
remove an import (see worklist), for example. - .&unknown_import
-
%EXPORT= ( '.&unknown_import' => sub { my ($blessed_export_def, $caller, $version, $symbol, $param_list_tail)= @_; #...
This callback is invoked for an unlisted symbol. It must return
undef
to indicate no error but no real export either (i.e. a pragmatic import) or a reference to the correct type of thing based on the name in$symbol
, ordie
if the$symbol
could not be handled. The default implementation indicates an error for any symbol. - .&unknown_type
-
%EXPORT= ( '.&unknown_type' => sub { my ($blessed_export_def, $caller, $version, $strange_import_param, $import_list_tail)= @_; #...
If the import list contains something that is not a scalar, then it is passed to this callback. The thing in question is
$strange_import_param
.This is handy for implementing modules that take a hash ref or other object in addition to export names. This can also be done by making it follow a pragmatic import, or looking for it in a
.&begin
pass.This callback must do whatever it needs to in your module. It doesn't return anything to the export engine (so
die
to fail). The callback may call$self->export
with more symbols, if it needs to do any real exporting. - .verbose_import
-
If true, it will print trace statements as the specifications are being processed, and explain what is actually being imported into modules. If false, it stays mute except for warnings or errors.
When importing is complete and
.verbose_import
is true, then.verbose_import
is decremented. This means that setting it to 1 will operate as a one-shot, only reporting details the first time it isuse
d. If you set it to 2, then two calls to this module'simport
will be be reported, and so on.If you don't define a
--verbose_import
key in the%EXPORT
definition, then this module will automatically define a--verbose_import
pragmatic import that will activate verbose mode if used.use ModuleName 2.0 qw/ --verbose_import foo bar/;
Of course, it doesn't take effect until after that
--verbose_import
parameter has been processed, so it will not report setup and things to its left.Any pragmas that refer to the import process itself rather than any resulting semantics of the module will begin with a double-dash.
- .warnings
-
If the value is true, then extra keys that are not known options are reported as warnings, and other possible typos are reported in the
%EXPORT
definition. If false, then it doesn't go out of its way to look for problems, speeding up the process.The default value, if this option is not given, is 1. You must specify
.warnings => 0,
to disable these warnings.
- user-defined and reserved
-
To prevent typos, when warnings are enabled, the
%EXPORT
definition is scanned for unknown options.If you derive from or otherwise extend
Exporter::VA
and wish to add more options, use option names beginning with capital letters (or a&
followed by a capital letter). All others are reserved for future versions of this module. (A capital can be any Unicode value with the IsUpper property.)Also, supply a method
check_user_option
in your derived class or use the.check_user_option
option to declare your additional options.
Quick guide to difference compared to classic Exporter
Also see the Exporter-VA-Convert.perl program, which will automatically read a module and tell you exactly what to change and show you the equivilent %EXPORT
definition.
With classic Exporter,
package SomeModule;
require Exporter;
@ISA = qw(Exporter);
becomes, with Exporter::VA
,
package SomeModule;
use Exporter::VA 1.1 ':normal';
The classic Exporter
@EXPORT_OK = qw/ foo bar /; # symbols to export on request
becomes with Exporter::VA
,
%EXPORT= (
'.plain' => [ qw/ foo bar /];
# ...
};
The classic Exporter
@EXPORT = qw/ baz quux /; # symbols to export by default
becomes a tag named :DEFAULT
, thus:
%EXPORT= (
'.plain' => [ qw/ :DEFAULT /];
':DEFAULT' => [ qw/ foo bar / ];
};
and listing them as :DEFAULT
doesn't releive you from having define the individual exports. Using .plain
is the simplest way to define the exports, and note that you don't have to re-list all of them, as it takes tag names too.
Likewise, any named tag is also listed as a key in the %EXPORT
list in this format.
Aliases and Non-Imported Calls
An alias specified in the %EXPORT
definition only works if it's imported. For example, if the %EXPORT
definition contained
foo => [ v1.0, 'foo_old', v2.0, 'foo_new' ],
bar => 'bar_internal',
fobble => \&figure_it_out,
and the main program used:
use ModuleName v1.5 qw(foo bar);
then the main code could call foo
and get ModuleName::foo_old
, and call bar
and get ModuleName::bar_internal
. But what happens if the main code explicitly calls ModuleName::foo
or doesn't import at all, and tries to call ModuleName::fobble
?
It will indeed attempt to call functions named ModuleName::foo
and ModuleName::fobble
, respectivly. That is not the same as what happens when calling through the imported symbol.
To handle this, simply arrange it so there is a function defined as ModuleName::foo
etc.
The best way to handle this is to assure that the directly-called functions have the identical semantics as the imported aliases.
This can be handled automatically, by having ModuleName
import AUTOLOAD
from Exporter::VA
. Then, a direct call to foo
will (if you don't happen to have an unrelated function called foo also!) land in AUTOLOAD
, which will automatically generate a suitable ModuleName::foo
. It will look up the caller's desired version at run-time and jump to either foo_old
or foo_new
as appropreate.
If you need to write your own AUTOLOAD
for the module for other reasons, you can incorporate this ability by calling the method autoload_symbol.
If you don't like the automatically-generated thunk, you can easily create your own using the underlying helper functions. In order to write a function foo
that checks the caller's desired version and calls the appropreate version, use the methods resolve and VERSION.
There is no automatic facility to do this for non-functions. You are better off using access methods instead of direct access to data values. But, you can accomplish much the same thing by using ties to a variable of the stated name, where the tie's implementation switches between underlying versions.
If a data structure changes, instead of versioning the export for the data item, have the new version remove the export of the data item and introduce an access method in its place.
Extending Exporter::VA
Using .&begin and .&end options
The easiest way to add some processing around this module's import
semantics is to use the .&begin
and .&end
options.
Writing Your Own Import Function
It is simplest to import the implementation of import
from Exporter::VA
. Anything you can do by wrapping it within a larger piece of code can be done using the .begin
and .end
options. You can also make changes by overriding various other methods in a derived class. If you do wish to write your own import
function, the generated one looks like this:
my $export_def; # found before function is generated
sub import
{
my $home= shift;
$export_def->setup ($home); # happens first time used.
my $module= _calling_client(); # does caller() in a loop 'till out of Exporter::VA.
my $version= $export_def->get_import_version();
$export_def->callback ('.&begin', $module, $version, '.&begin', \@_);
@_ = ':DEFAULT' if (!@_ && defined $export_def->{':DEFAULT'});
$export_def ->export ($module, $version, \@_);
$export_def->callback ('.&end', $module, $version, '.&begin', \@_);
$export_def->_process_worklist();
}
See this module's own pragmas for information on customizing this generated code without rewriting it or cutting and pasting it.
The VERSION function
When a module uses Exporter::VA
, it typically imports a generated VERSION
function. This makes the versioning capabilities work, as ModuleName::VERSION
will not simply verify that the requested version is less than the module's version, but will record the per-client desired version number for subsequent use.
If the module doesn't import the generated VERSION
function from Exporter::VA
, then the versioning features will not be available, and version numbers specified in use
statements will be silently ignored by Exporter::VA
, since it will never see it.
Inheriting from Exporter::VA
This module is fundimentally designed to allow custimization via deriving from it. However, the way it is used is unique, and making it behave as an object needs a little explaining.
The import
function called by use
does not contain a this/self parameter, but only has the list of imports. In order to have all its helper functions make virtual calls and thus allow replacement, an object is introduced as soon as possible.
The object is simply the %EXPORT
definition. As you can see from the listing of import
above, A reference to the %EXPORT
definition is blessed into Exporter::VA
, and all subsequent functions are dispatched through it.
If you derive from Exporter::VA
, you must bless the object into your derived package instead, and then your function overrides will be used.
Since import
has no object, it has the package name hard-coded into it. If you derive from Exporter::VA
, you could supply the definition of import
from your derived class as well. But if that's the only change you need, you can use this module's own -derived
pragma. This is an example of using a pragmatic import to paramiterize the generation of an imported function.
package Extend;
use Exporter::VA ();
@ISA= ('Exporter::VA');
sub resolve { ... # override what I need to change here
package ModuleName;
use Exporter::VA qw/ -derived Extend import AUTOLOAD /;
%EXPORT= { ... #
# proceed writing my module
Methods
autoload_symbol
autoload_symbol ($blessed_export_def, $symbol, @extras)
Call this to implement AUTOLOAD
, or pre-generate the thunks. Calling this will generate a sub named $symbol
into the module where the $blessed_export_def
is from that will redirect to the proper function based on its immediate caller at run-time.
Note that $symbol
must name a function listed in the %EXPORT
definition, and you must <I>leave off</I> the '&' sigil.
Any extra arguments are passed as the $param_list_tail
if a callback is involved. This lets you pass parameters if need be, as would normally be found following the symbol name in the import list. However, it doesn't seem like a good idea to have ordinarily-named import symbols taking parameters (they should begin with a dash, for clarity).
check_user_option
$errormessage= check_user_option ($blessed_export_def, $optionname)
Supply this function in a derived class if you are adding any user-defined options. If checking is enabled, then any hash keys in the %EXPORT
definition that begin with a .
or .&
followed by a capital letter are passed to this function for validation.
Return undef
if the option is OK, and no warning will be emitted. Return a string and it will be incorporated into the warning message.
The built-in base implementation will call the code in .check_user_option
if present, or otherwise report a warning on all parameters it checks.
dump
dump ($blessed_export_def)
This prints a debug dump of the object to the VERBOSE
handle. This might be handy to call from your callbacks (or pragmatic imports) to see what's going on. This is called by the --dump
pragma.
export
export ($blessed_export_def, $caller, $version, $item_or_list)
This will export a single item or a list of items. $item_or_list
can be a single item (as from an import list) or a reference to a whole list. Each item is processed using the full rules of the %EXPORT
definition.
You can call this from pragmatic callbacks or other places to explicitly export something at will.
The specified item(s) are resolved and then placed into the $caller
's package.
find_export_def ($caller, $import_list)
Not virtual, but regular function.
This is used by import
to locate the %EXPORT
definition. If it is found in the $import_list
, it is removed from the list. If not found in the list, then it looks for the package global %EXPORT
in the $caller
. Either way, it returns the hash ref.
You only need to call this yourself if implementing your own import
.
resolve
$ref= resolve ($blessed_export_def, $caller, $version, $item, $import_param_tail)
This will look for $item
based on the %EXPORT
definition, and return a reference to the thing to export under that name based on the specified $version
and possibly the $caller
. The $caller
and $import_param_tail
are not needed directly, but will be passed to callbacks.
worklist
$hashref= worklist ($blessed_export_def)
This return a reference to the work list, used during the import list processing.
As each item in the import list is processed, the result doesn't get placed immediatly into the caller's namespace. Rather, it is added to this work list in the form symbolname => ref
. This allows for subsequent pragmatic options or .&end
or future features to modify the list before the work it represents is comitted.
TODO: decide how to keep the list ordered.
Exports
special
If a parameter to Exporter::VA
's own import
is not a string but a hash ref, then it is taken as the argument to the -def
pragma.
The package global file handle Exporter::VA::VERBOSE
is used for verbose-mode output messages. It is initially aliased to STDERR
, but may be redirected using glob assignment.
functions
- AUTOLOAD
- import
- normalize_vstring
-
This takes the argument which represents a version number, and returns a normalized form of it. The normalized form allows for version comparisons using string relational operators, including
eq
. That is, various ways of specifying the same version identifier are all converted to the same canonocal form. For example,v1.0
,"1.0.0.0"
,1.0
all refer to the same version and will return the same normalized string.The following forms are accepted:
A string that is an ASCII representation of a dotted number is converted to a v-string. If you have a v-string that contains only values that happen to be ASCII digits and dots, such as
v51.46.50
, then it will think it's the ASCII string for"3.2"
and convert it tov3.2
. To disambiguate, add an extra.0
on the end, which does not change the meaning thanks to normalization. That is,v51.46.50.0
means the same thing asv51.46.50
. Specifically (and this is subject to change), any string that contains characters in the range of\x0
through\x1f
, which are non-printable control codes, is considered to be a v-string. A string that contains no characters in this range is assumed to be a string representation of some kind. Since most version numbers are small, this is a natural way to distinguish them.Using a float for a vstring 2.3 gives v2.3, not v2.300. That is, it doesn't follow the 3-digit rule, but simple stringification. Distinghishing a float literal from a string literal would require a module not supplied with Perl 5.6 (but is available in 5.8). Few people seem to use the 3-digit rule anyway. It's best to just remember to always use the v, or use quotes. In Perl 5.8 this may generate a warning in the future.
After converting the input representation to a v-string, it is put into canonocal form to properly allow
eq
comparisons. Specifically, trailing zeros are removed, except it will always have at least two digits. Sov2
andv2.0.0.0.0.0.0
both becomev2.0
.This function is used by the module to allow version representations in your chosen format. It may be exported, so you can easily use this public function yourself, too.
- VERSION
-
$v= Module->VERSION; # get version info Module->VERSION ($v); # set/verify version info Module->VERSION ($v, $caller); # set/verify version info for $caller $v= Module->VERSION (undef, $caller); # get version info for $caller
The
VERSION
function has a pre-defined meaning to Perl. When a version number "indirect argument" parameter is used, it is called as an argument to the Module'sVERSION
function. That function is intended to die if the version is unsuitable.Instead of simply checking that the supplied version is <= the Module's
$VERSION
, this implementation ofVERSION
will note the version asked for by the caller. This information is the basis for all features that make use of knowing what version a module's client is expecting, such as to present different import lists or enable backward-compatible behavior.Besides noting the version,
VERSION
still verifies it. The desired version is still checked against the upper-limit of the Module's$VERSION
, and the.allowed_VERSIONS
setting if present.Unlike the supplied
UNIVERSAL::VERSION
, this one can handle any supported format for the value of$VERSION
(seenormalize_vstring
).If called with no arguments, <VERSION> returns the Module's version. It does this with caller awareness, as different calling modules may have specified different versions of the use'd Module. If you ask for the version but never specified a desired version, it takes the module's
$VERSION
(or the.default_VERSION
setting), acting as though that was the version you asked for all along.Note that it always returns a normalized v-string, regardless of what format you may have used to set or specify the version.
So, this function is used internally by the semantics of use (or require) to set the per-module version, and is also to obtain the per-module version for any (and all) need for this information. If a function within the module wants to know if it should emulate an old version or not, it can call its own VERSION function and find out what the caller (first caller up the chain that's outside of this Module) is expecting.
As the sole interface for this information, the
VERSION
function has one addional bit of flexibility. You can call it with a 3rd argument to specify a client module, rather than using the caller. So,package B; use Module v2.7; sub foo { my $B_version= Module->VERSION(); # gets v2.7 my $Henry_version= Module->VERSION (undef, 'Henry'); # find out what Henry's doing. }
Note that you specify
undef
as the version argument so that you can supply the optional extra argument and still use the "get" form of the function. Presence of the version argument triggers the "set" form.
tags
The tag :normal
will import the normal 3 functions, import
, AUTOLOAD
, and VERSION
. This is not the :DEFAULT
on a matter of principle, that module writers are encouraged not to export things by default and it is ironic to violate this in the exporter itself.
pragmas
- -def hashref
-
This will supply the
%EXPORT
definition, as opposed to having it found as a package global in the caller. You can leave off the-def
actually, and simply provide a hash ref argument to import (via theuse
statement). The named pragma is provided for completeness sake.use ModuleName 0.2 ( -def => \%myhash, qw/foo bar/ );
As a special rule, this parameter may be located anywhere in the import list; it does not have to come first, even though parameters are normally processed left-to-right. This module goes out of its way to do this because it is nicer to write it last, in producing readable code.
use Exporter::VA ('import', 'VERSION', { foo => \\&internal_foo, bar => \\&internal_bar, # long list } );
You have the option of putting the regular parameters first, so they are not lost at the end of the long literal hash.
- -derived name
-
The pragmatic import
-derived name
will customize the generated import function to contain the specified name as the package to bless the object into. This is handy for deriving fromExporter::VA
. For example:package ModuleName; use Exporter::VA qw/-derived ExpEnhancement import AUTOLOAD/;
note that this only affects items farther to the right in the list, so it makes sense to always put
-derived
first. - --dump
-
This will display the state of the
%EXPORT
definition hash to theVERBOSE
file handle. This will include the items specified by the module doing the exporting, defaults expanded or filled in, and internal state values. - --verbose_import
-
See .verbose. This increments the
.verbose
value.
Compatibility
Platforms
It uses only pure Perl and no non-basic modules, so it ought to work on any platform.
I'd appreciate it if anyone using a different configuration (not listed below) let me know that the test1.perl script works properly and that there are no issues. If there are issues, I'm even more interested!
Tested on:
Exporter::VA version 1.3.0.1 on Perl 5.6.1 (AS 633, Windows 2000)
Exporter::VA version 1.3.0.1 on Perl 5.8.0 (AS 804, Windows 2000)
... others wanted! CPAN testers haven't reported anything since I made the module compatible with CPANPLUS.
Unicode / utf8
In Perl 5.6, a compiled regex only works properly with strings of the same discipline (byte-oriented or character oriented). So, how should this module be compiled, with or without Unicode regex's? Since the strings being matched will be Perl identifier names, and non-ASCII identifiers are only allowed when use utf8
is in effect, that is the natural choice. Without utf8 mode, you have no business importing a symbol that contains a Unicode name, anyway. Note that if you do pass byte-oriented strings to the import()
function that contain values >127, you'll get warnings about bad UTF-8 encoding from the module. Don't do that. You have no business using such characters in identifier names, and you'll have to work-around that for pragmatic import names beginning with a dash (which don't have to be legal identifiers). The regex issue is fixed in Perl 5.8, so it is no longer a problem moving forward.
Threads
The Exporter::VA module is oblivious to threads. Modules are normally imported at the beginning of execution before threads are started, so there is not much incentive to verify the matter. But if you do call import()
for the same module from two different threads, the %EXPORT
definition should be copied to each thread. As of writing, I'm unaware of how symbol tables are shared (or not). Anyone who explores the matter or stresses the module in this regard, please let me know.
Caveats and known issues
not implemented
-derived pragma not implemented yet.
not tested
Not in unit test: check_user_option() semantics.
Not in unit test: warnings if typo in export definition.
Not in unit test: extra arguments to autoload_symbol
passed to callback in %EXPORT
definition. Don't do that anyway!
Ideas for Future
Allow tags to be callbacks. That could support a dynamic :all tag, as well as dynamic lists in general. You can manage it now with some effort... a pragmatic import calls export() itself to export a whole list of things, and if you really want the tag syntax, define a tag that expands to that one pragma.
Allow tag's definition to contain other tags, not just symbols.
COPYRIGHT
Copyright 2003 by John M. Dlugosz. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
HISTORY
See the README.txt file for detailed history.