1Sub::Exporter::CookbookU(s3e)r Contributed Perl DocumentaStuibo:n:Exporter::Cookbook(3)
2
3
4
6 Sub::Exporter::Cookbook - useful, demonstrative, or stupid
7 Sub::Exporter tricks
8
10 Sub::Exporter is a fairly simple tool, and can be used to achieve some
11 very simple goals. Its basic behaviors and their basic application
12 (that is, "traditional" exporting of routines) are described in
13 Sub::Exporter::Tutorial and Sub::Exporter. This document presents
14 applications that may not be immediately obvious, or that can
15 demonstrate how certain features can be put to use (for good or evil).
16
18 Exporting Methods as Routines
19 With Exporter.pm, exporting methods is a non-starter. Sub::Exporter
20 makes it simple. By using the "curry_method" utility provided in
21 Sub::Exporter::Util, a method can be exported with the invocant built
22 in.
23
24 package Object::Strenuous;
25
26 use Sub::Exporter::Util;
27 use Sub::Exporter -setup => {
28 exports => [ objection => curry_method('new') ],
29 };
30
31 With this configuration, the importing code may contain:
32
33 my $obj = objection("irrelevant");
34
35 ...and this will be equivalent to:
36
37 my $obj = Object::Strenuous->new("irrelevant");
38
39 The built-in invocant is determined by the invocant for the "import"
40 method. That means that if we were to subclass Object::Strenuous as
41 follows:
42
43 package Object::Strenuous::Repeated;
44 @ISA = 'Object::Strenuous';
45
46 ...then importing "objection" from the subclass would build-in that
47 subclass.
48
49 Finally, since the invocant can be an object, you can write something
50 like this:
51
52 package Cypher;
53 use Sub::Exporter -setup => {
54 exports => [ encypher => curry_method ],
55 };
56
57 with the expectation that "import" will be called an instantiated
58 Cypher object:
59
60 BEGIN {
61 my $cypher = Cypher->new( ... );
62 $cypher->import('encypher');
63 }
64
65 Now there is a globally-available "encypher" routine which calls the
66 encypher method on an otherwise unavailable Cypher object.
67
68 Exporting Methods as Methods
69 While exporting modules usually export subroutines to be called as
70 subroutines, it's easy to use Sub::Exporter to export subroutines meant
71 to be called as methods on the importing package or its objects.
72
73 Here's a trivial (and naive) example:
74
75 package Mixin::DumpObj;
76
77 use Data::Dumper;
78
79 use Sub::Exporter -setup => {
80 exports => [ qw(dump) ]
81 };
82
83 sub dump {
84 my ($self) = @_;
85 return Dumper($self);
86 }
87
88 When writing your own object class, you can then import "dump" to be
89 used as a method, called like so:
90
91 $object->dump;
92
93 By assuming that the importing class will provide a certain interface,
94 a method-exporting module can be used as a simple plugin:
95
96 package Number::Plugin::Upto;
97 use Sub::Exporter -setup => {
98 into => 'Number',
99 exports => [ qw(upto) ],
100 groups => [ default => [ qw(upto) ] ],
101 };
102
103 sub upto {
104 my ($self) = @_;
105 return 1 .. abs($self->as_integer);
106 }
107
108 The "into" line in the configuration says that this plugin will export,
109 by default, into the Number package, not into the "use"-ing package.
110 It can be exported anyway, though, and will work as long as the
111 destination provides an "as_integer" method like the one it expects.
112 To import it to a different destination, one can just write:
113
114 use Number::Plugin::Upto { into => 'Quantity' };
115
116 Mixing-in Complex External Behavior
117 When exporting methods to be used as methods (see above), one very
118 powerful option is to export methods that are generated routines that
119 maintain an enclosed reference to the exporting module. This allows a
120 user to import a single method which is implemented in terms of a
121 complete, well-structured package.
122
123 Here is a very small example:
124
125 package Data::Analyzer;
126
127 use Sub::Exporter -setup => {
128 exports => [ analyze => \'_generate_analyzer' ],
129 };
130
131 sub _generate_analyzer {
132 my ($mixin, $name, $arg, $col) = @_;
133
134 return sub {
135 my ($self) = @_;
136
137 my $values = [ $self->values ];
138
139 my $analyzer = $mixin->new($values);
140 $analyzer->perform_analysis;
141 $analyzer->aggregate_results;
142
143 return $analyzer->summary;
144 };
145 }
146
147 If imported by any package providing a "values" method, this plugin
148 will provide a single "analyze" method that acts as a simple interface
149 to a more complex set of behaviors.
150
151 Even more importantly, because the $mixin value will be the invocant on
152 which the "import" was actually called, one can subclass
153 "Data::Analyzer" and replace only individual pieces of the complex
154 behavior, making it easy to write complex, subclassable toolkits with
155 simple single points of entry for external interfaces.
156
157 Exporting Constants
158 While Sub::Exporter isn't in the constant-exporting business, it's easy
159 to export constants by using one of its sister modules,
160 Package::Generator.
161
162 package Important::Constants;
163
164 use Sub::Exporter -setup => {
165 collectors => [ constants => \'_set_constants' ],
166 };
167
168 sub _set_constants {
169 my ($class, $value, $data) = @_;
170
171 Package::Generator->assign_symbols(
172 $data->{into},
173 [
174 MEANING_OF_LIFE => 42,
175 ONE_TRUE_BASE => 13,
176 FACTORS => [ 6, 9 ],
177 ],
178 );
179 }
180
181 Then, someone can write:
182
183 use Important::Constants 'constants';
184
185 print "The factors @FACTORS produce $MEANING_OF_LIFE in $ONE_TRUE_BASE.";
186
187 (The constants must be exported via a collector, because they are
188 effectively altering the importing class in a way other than installing
189 subroutines.)
190
191 Altering the Importer's @ISA
192 It's trivial to make a collector that changes the inheritence of an
193 importing package:
194
195 use Sub::Exporter -setup => {
196 collectors => { -base => \'_make_base' },
197 };
198
199 sub _make_base {
200 my ($class, $value, $data) = @_;
201
202 my $target = $data->{into};
203 push @{"$target\::ISA"}, $class;
204 }
205
206 Then, the user of your class can write:
207
208 use Some::Class -base;
209
210 and become a subclass. This can be quite useful in building, for
211 example, a module that helps build plugins. We may want a few
212 utilities imported, but we also want to inherit behavior from some base
213 plugin class;
214
215 package Framework::Util;
216
217 use Sub::Exporter -setup => {
218 exports => [ qw(log global_config) ],
219 collectors => { _become_plugin => \'_become_plugin' },
220 groups => [ -plugin => [ qw(log global_config _become_plugin) ]
221 };
222
223 sub _become_plugin {
224 my ($class, $value, $data) = @_;
225
226 my $target = $data->{into};
227 push @{"$target\::ISA"}, $class->plugin_base_class;
228 }
229
230 Now, you can write a plugin like this:
231
232 package Framework::Plugin::AirFreshener;
233 use Framework::Util -plugin;
234
235 Eating Exporter.pm's Brain
236 You probably shouldn't actually do this in production. It's offered
237 more as a demonstration than a suggestion.
238
239 sub exporter_upgrade {
240 my ($pkg) = @_;
241 my $new_pkg = "$pkg\::UsingSubExporter";
242
243 return $new_pkg if $new_pkg->isa($pkg);
244
245 Sub::Exporter::setup_exporter({
246 as => 'import',
247 into => $new_pkg,
248 exports => [ @{"$pkg\::EXPORT_OK"} ],
249 groups => {
250 %{{"$pkg\::EXPORT_TAG"},
251 default => [ @{"$pkg\::EXPORTS"} ],
252 },
253 });
254
255 @{"$new_pkg\::ISA"} = $class;
256 return $new_pkg;
257 }
258
259 This routine, given the name of an existing package configured to use
260 Exporter.pm, returns the name of a new package with a
261 Sub::Exporter-powered "import" routine. This lets you write:
262
263 BEGIN {
264 require Toolkit;
265 exporter_upgrade('Toolkit')->import(exported_sub => { -as => 'foo' })
266 }
267
268 If you're feeling particularly naughty, this routine could have been
269 declared in the UNIVERSAL package, meaning you could write:
270
271 BEGIN {
272 require Toolkit;
273 Toolkit->exporter_upgrade->import(exported_sub => { -as => 'foo' })
274 }
275
276 The new package will have all the same exporter configuration as the
277 original, but will support export and group renaming, including
278 exporting into scalar references. Further, since Sub::Exporter uses
279 "can" to find the routine being exported, the new package may be
280 subclassed and some of its exports replaced.
281
283 Ricardo SIGNES, "<rjbs@cpan.org>"
284
286 Copyright 2007, Ricardo SIGNES. This is free software; you can
287 redistribute it and/or modify it under the same terms as Perl itself.
288
289
290
291perl v5.10.1 2008-11-21 Sub::Exporter::Cookbook(3)