How can I create a module that imports many modules for the user?

I have a rather complicated data structure implemented in Perl. It was broken into about 20 classes. Basically, anytime you want to use one of these classes, you need to use all of them.

Right now, if someone wants to use this data structure, they need to do something like:

use Component::Root; use Component::Foo; use Component::Bar; use Component::Baz; use Component::Flib; use Component::Zen; use Component::Zen::Foo; use Component::Zen::Bar; use Component::Zen::Baz; ... # 15 more of these... use Component::Last; 

to be able to manipulate all its parts. How can I write a module that does this for the user, so all they need to do is

 use Component; 

to import all other modules?

In this particular case, the modules are all classes and have no export.

+4
source share
5 answers

If these are just classes (i.e. they don’t export any functions or variables when you use them), then all that really matters is that they were loaded.

Just create Component.pm :

 package Component; our $VERSION = '1.00'; use Component::Root; use Component::Foo; use Component::Bar; use Component::Baz; use Component::Flib; use Component::Zen; use Component::Zen::Foo; use Component::Zen::Bar; use Component::Zen::Baz; ... # 15 more of these... use Component::Last; 1; # Package return value 

You don't need an Exporter or anything like that.

However, instead of having a module that is nothing but use statements, it probably makes sense to place these use statements in a node root class or in a module that creates a data structure, i.e. people will want to say:

 use Component::Root; my $root = Component::Root->new(...); 

or

 use Component qw(build_structure); my $root = build_structure(...); 

depending on how your data structure is usually created. For people, it can be a bit confusing:

 use Component; my $root = Component::Root->new(...); 

but it really depends on how your API looks. If there are several classes that people could call new on, then use Component might be the way to go.

+6
source
  • You can use the export_to_level method for all those Exporter s packages.

     MyPackage->export_to_level($where_to_export, $package, @what_to_export); 
  • You can also export all imported characters.

     use PackageA qw<Huey Dewey Louie>; ... our @ISA = qw<Exporter>; #inherit Exporter our @EXPORT = qw<Huey Dewey Louie>; 
  • However, if you do not want to export any characters and just want to load the modules, simply include these use instructions above, and any package in the process will be able to create them as classes, say, if they were all OO modules.

    Provided that they were successfully loaded, they will exist in %INC and the symbol table.

+1
source

Moose :: Exporter seems to do this, although all of your other modules will also have to use it.

In Component :

 Moose::Exporter->setup_import_methods( also => [qw/Component::Root Component::..*/], ); 
0
source

If the modules do not export anything and do not have an import method (the same requirements as for cjm answer), you just need to load the modules without import:

 package Component; our $VERSION = '1.00'; require Component::Root; require Component::Foo; require Component::Bar; require Component::Baz; require Component::Flib; require Component::Zen; require Component::Zen::Foo; require Component::Zen::Bar; require Component::Zen::Baz; ... # 15 more of these... require Component::Last; 1; # Package return value 

Users of the module simply do the following:

 require Component; 

If, however, some modules are exported, you will have to call their import method. Thus, you have added the import method to your Component module, which will call them:

 sub import { Component::Root->import; Component::Foo->import; ... } 

and therefore, users of the module will use it:

 use Component; 

Note that you may have to use some other tricks if the imported module needs to insert characters in the context of the importer. See for example how POE import does this.

0
source

The Modern :: Perl module includes: "enable all the functions of Modern Perl with a single command", where this command

 use Modern::Perl; 

and these functions

Currently, this allows only strict and warning pragmas, as well as all the functions available in Perl 5.10. It also provides C3 method resolution order; see perldoc mro for an explanation.

This is a lot for one line of code, which according to the perlmod documentation is exactly equivalent

 BEGIN { require Module; import Module; } 

Consider the Modern :: Perl implementation :

 package Modern::Perl; our $VERSION = '1.03'; use 5.010_000; use strict; use warnings; use mro (); use feature (); sub import { warnings->import(); strict->import(); feature->import( ':5.10' ); mro::set_mro( scalar caller(), 'c3' ); } 1; # End of Modern::Perl 

To adapt this to your situation, from your top-level module use all the other modules that you want to load and invoke their import, if any, from MyTopLevelModule::import .

Please note that you do not have to copy

 use 5.010_000; 

at MyTopLevelModule.pm , but that would be a great idea! According to use documentation :

In a peculiar form, use VERSION VERSION can be either a positive decimal, such as 5.006 , which will be compared with $] , or a v-string of the form v5.6.1 , which will be compared to $^V (aka $PERL_VERSION ). An exception occurs if VERSION is larger than the version of the current Perl interpreter; Perl will not try to parse the rest of the file. Compare with require , which can perform a similar check at runtime.

0
source

All Articles