4 Sub::Exporter::Cookbook - useful, demonstrative, or stupid Sub::Exporter tricks
8 Sub::Exporter is a fairly simple tool, and can be used to achieve some very
9 simple goals. Its basic behaviors and their basic application (that is,
10 "traditional" exporting of routines) are described in
11 L<Sub::Exporter::Tutorial> and L<Sub::Exporter>. This document presents
12 applications that may not be immediately obvious, or that can demonstrate how
13 certain features can be put to use (for good or evil).
17 =head2 Exporting Methods as Routines
19 With Exporter.pm, exporting methods is a non-starter. Sub::Exporter makes it
20 simple. By using the C<curry_method> utility provided in
21 L<Sub::Exporter::Util>, a method can be exported with the invocant built in.
23 package Object::Strenuous;
25 use Sub::Exporter::Util;
26 use Sub::Exporter -setup => {
27 exports => [ objection => curry_method('new') ],
30 With this configuration, the importing code may contain:
32 my $obj = objection("irrelevant");
34 ...and this will be equivalent to:
36 my $obj = Object::Strenuous->new("irrelevant");
38 The built-in invocant is determined by the invocant for the C<import> method.
39 That means that if we were to subclass Object::Strenuous as follows:
41 package Object::Strenuous::Repeated;
42 @ISA = 'Object::Strenuous';
44 ...then importing C<objection> from the subclass would build-in that subclass.
46 Finally, since the invocant can be an object, you can write something like
50 use Sub::Exporter -setup => {
51 exports => [ encypher => curry_method ],
54 with the expectation that C<import> will be called an instantiated Cypher
58 my $cypher = Cypher->new( ... );
59 $cypher->import('encypher');
62 Now there is a globally-available C<encypher> routine which calls the encypher
63 method on an otherwise unavailable Cypher object.
65 =head2 Exporting Methods as Methods
67 While exporting modules usually export subroutines to be called as subroutines,
68 it's easy to use Sub::Exporter to export subroutines meant to be called as
69 methods on the importing package or its objects.
71 Here's a trivial (and naive) example:
73 package Mixin::DumpObj;
77 use Sub::Exporter -setup => {
78 exports => [ qw(dump) ]
86 When writing your own object class, you can then import C<dump> to be used as a
87 method, called like so:
91 By assuming that the importing class will provide a certain interface, a
92 method-exporting module can be used as a simple plugin:
94 package Number::Plugin::Upto;
95 use Sub::Exporter -setup => {
97 exports => [ qw(upto) ],
98 groups => [ default => [ qw(upto) ] ],
103 return 1 .. abs($self->as_integer);
106 The C<into> line in the configuration says that this plugin will export, by
107 default, into the Number package, not into the C<use>-ing package. It can be
108 exported anyway, though, and will work as long as the destination provides an
109 C<as_integer> method like the one it expects. To import it to a different
110 destination, one can just write:
112 use Number::Plugin::Upto { into => 'Quantity' };
114 =head2 Mixing-in Complex External Behavior
116 When exporting methods to be used as methods (see above), one very powerful
117 option is to export methods that are generated routines that maintain an
118 enclosed reference to the exporting module. This allows a user to import a
119 single method which is implemented in terms of a complete, well-structured
122 Here is a very small example:
124 package Data::Analyzer;
126 use Sub::Exporter -setup => {
127 exports => [ analyze => \'_generate_analyzer' ],
130 sub _generate_analyzer {
131 my ($mixin, $name, $arg, $col) = @_;
136 my $values = [ $self->values ];
138 my $analyzer = $mixin->new($values);
139 $analyzer->perform_analysis;
140 $analyzer->aggregate_results;
142 return $analyzer->summary;
146 If imported by any package providing a C<values> method, this plugin will
147 provide a single C<analyze> method that acts as a simple interface to a more
148 complex set of behaviors.
150 Even more importantly, because the C<$mixin> value will be the invocant on
151 which the C<import> was actually called, one can subclass C<Data::Analyzer> and
152 replace only individual pieces of the complex behavior, making it easy to write
153 complex, subclassable toolkits with simple single points of entry for external
156 =head2 Exporting Constants
158 While Sub::Exporter isn't in the constant-exporting business, it's easy to
159 export constants by using one of its sister modules, Package::Generator.
161 package Important::Constants;
163 use Sub::Exporter -setup => {
164 collectors => [ constants => \'_set_constants' ],
168 my ($class, $value, $data) = @_;
170 Package::Generator->assign_symbols(
173 MEANING_OF_LIFE => 42,
180 Then, someone can write:
182 use Important::Constants 'constants';
184 print "The factors @FACTORS produce $MEANING_OF_LIFE in $ONE_TRUE_BASE.";
186 (The constants must be exported via a collector, because they are effectively
187 altering the importing class in a way other than installing subroutines.)
189 =head2 Altering the Importer's @ISA
191 It's trivial to make a collector that changes the inheritence of an importing
194 use Sub::Exporter -setup => {
195 collectors => { -base => \'_make_base' },
199 my ($class, $value, $data) = @_;
201 my $target = $data->{into};
202 push @{"$target\::ISA"}, $class;
205 Then, the user of your class can write:
207 use Some::Class -base;
209 and become a subclass. This can be quite useful in building, for example, a
210 module that helps build plugins. We may want a few utilities imported, but we
211 also want to inherit behavior from some base plugin class;
213 package Framework::Util;
215 use Sub::Exporter -setup => {
216 exports => [ qw(log global_config) ],
217 collectors => { _become_plugin => \'_become_plugin' },
218 groups => [ -plugin => [ qw(log global_config _become_plugin) ]
222 my ($class, $value, $data) = @_;
224 my $target = $data->{into};
225 push @{"$target\::ISA"}, $class->plugin_base_class;
228 Now, you can write a plugin like this:
230 package Framework::Plugin::AirFreshener;
231 use Framework::Util -plugin;
233 =head2 Eating Exporter.pm's Brain
235 You probably shouldn't actually do this in production. It's offered more as a
236 demonstration than a suggestion.
238 sub exporter_upgrade {
240 my $new_pkg = "$pkg\::UsingSubExporter";
242 return $new_pkg if $new_pkg->isa($pkg);
244 Sub::Exporter::setup_exporter({
247 exports => [ @{"$pkg\::EXPORT_OK"} ],
249 %{{"$pkg\::EXPORT_TAG"},
250 default => [ @{"$pkg\::EXPORTS"} ],
254 @{"$new_pkg\::ISA"} = $class;
258 This routine, given the name of an existing package configured to use
259 Exporter.pm, returns the name of a new package with a Sub::Exporter-powered
260 C<import> routine. This lets you write:
264 exporter_upgrade('Toolkit')->import(exported_sub => { -as => 'foo' })
267 If you're feeling particularly naughty, this routine could have been declared
268 in the UNIVERSAL package, meaning you could write:
272 Toolkit->exporter_upgrade->import(exported_sub => { -as => 'foo' })
275 The new package will have all the same exporter configuration as the original,
276 but will support export and group renaming, including exporting into scalar
277 references. Further, since Sub::Exporter uses C<can> to find the routine being
278 exported, the new package may be subclassed and some of its exports replaced.
282 Ricardo SIGNES, C<< <rjbs@cpan.org> >>
286 Copyright 2007, Ricardo SIGNES. This is free software; you can redistribute
287 it and/or modify it under the same terms as Perl itself.