In discussing versioning exports, I realized that the fundimental feature lacking in Exporter is the ability to have the internal and exported name differ. That is, an alias ability.
Versioning then is an application of using different aliases for different versions.
So I'm tennitivly calling this module Exporter::VA, for Version and Alias abilities.
Here is the user interface; that is, how a module author takes advantage of these features.
There are several kinds of information: as with the traditional system, there are symbols that are allowed to export, a subset of those that are default, and tags for named sets of symbols.
I want to have aliases that differ by version, as well as the (hopefully common) case of changing which symbols are exported by default based on version.
To that end, I've combined all the information into one hash. Here is an example:
The %EXPORT package variable is a set of hash pairs. If the key begins with a : then it is a "tag", described below. If it is an identifier name or begins with a sigel, it is a symbol name.use Exporter::VA; %EXPORT= ( foo => [ v1.0, 'foo_old', v2.0, 'foo_new' ], bar => 'bar_internal', baz => 'baz', fobble => \&figure_it_out, # parameter list is (caller, version, sy +mbol, param-list tail) $x => '$x', :tagname => [ 'foo', 'bar' ], :DEFAULT => [ v1.0, ':_old_imports', v2.3, ':_new_imports' ], :_old_imports => [ 'foo', 'bar', 'baz', 'fobble' ], :_new_imports => [ 'fobble' ] ); Exporter::VA::plain qw/ baz $x /;
The value may be the name of the internal symbol; a code reference; or an array ref.
If simply a string, it is the name by which the symbol is defined within the module. foo => 'foo_x' means to take the package's &foo_x and make it known as &foo in the caller's namespace. If the value name is equal to the key name, then no renaming is done (see Exporter::VA::plain below).
If the value is a list, the list alternates v-strings and symbol names. The symbol name will be taken when it appears between two v-strings such that the desired version is >= to the left and < the right.
If the value is a code ref, then it is called to figure it out at run time. It must return a reference to the proper type of thing, and that will be entered into the caller's namespace. It is called with the caller's package name, desired version v-string, the symbol name, and a reference to the rest of the import parameter list. The last allows the callback to pull more arguments (and delete them), or otherwise modify the remainder of the list.
The value is a list of names (symbol names and other tag names are allowed) or a list of alternating v-strings and tag names.
If a list of names, the list replaces the tag in the import parameter list and processing continues with the expanded content so nested tag lists are handled.
If a list of alternating v-strings and tag names, the logic is like that for symbol names. The tag is replaced by the other tag based on the desired version, and processing continues with that tag.
The :DEFAULT tag is used if an empty argument list is imported. It is just like any other tag, just taken as a default.
So, the function call Exporter::VA::plain qw/ baz $x /; will populate these simple entries. Each argument to plain is added as an entry to %EXPORT whose value is the same as the tag.
This thing only imports. This issue is different, but this thing will help a little.
If you indeed write a sub named foo, it could check the caller and decide at run time what to do based on which version the caller asked for.
To this end, the package variable %EXPORT_CALLERS associates importers with v-strings as supplied in their use statement.
The function Exporter::VA::resolve (symbol, optional-vstring) may also be used to traverse the %EXPORT data for you. If the v-string is omitted, it is looked up based on the caller's package.
In reply to Module Design strawman - Exporter::VA by John M. Dlugosz
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |