File Coverage

blib/lib/WWW/Mechanize/Plugin/Cookbook.pm
Criterion Covered Total %
statement 3 3 100.0
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 4 4 100.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             WWW::Mechanize::Plugin::Cookbook - how to write plugins for WWW::Mechanize::Pluggable
4              
5             =head1 DESCRIPTION
6              
7             This document describes what a C plugin is,
8             how they work in connection with the base module, and gives examples
9             of how one would design a new plugin.
10              
11             =over 4
12              
13             This cookbook addresses the current state of the C interface;
14             future versions are expected to greatly streamline the process of creating
15             plugins and hooks.
16              
17             =back
18              
19             =head1 PLUGIN BASICS
20              
21             A plugin is basically as specially-named package that is automatically loaded
22             by a parent class. This document outlines the interface between
23             C and its plugin classes.
24              
25             =head2 Flow of Control
26              
27             When C is loaded, it searches C<@INC> for
28             modules whose names begin with C and calls
29             C for the package, using the arguments supplied on
30             C's own C line. This allows you to
31             parameterize the plugins if you wish.
32              
33             When a C object is instantiated, its
34             C method calls each of the plugins' C method.
35             Typically, C exports methods back into
36             the caller's namespace, and also calls C and C
37             to wrap any of C's methods it desires.
38              
39             When a C method is called, C's
40             C takes control. It calls any pre-hooks that have been installed
41             for the method; if any of them return a true value, the actual method
42             call is skipped. C then calls the method
43             (if it should) using the same context in which the method was originally
44             callled, saving the return value. The post-hooks are then called, and the
45             return value from the method is returned to the original caller.
46              
47             =head2 What you can do
48              
49             Essentially, you now have complete control over what any method in the base
50             class does. You can
51              
52             =over 4
53              
54             =item * alter the parameter list
55              
56             =item * process the call yourself
57              
58             =item * conditionally get involved, or not
59              
60             =item * post-process the results after the call
61              
62             =back
63              
64             =head1 API TO WWW::MECHANIZE::PLUGGABLE
65              
66             =head2 import
67              
68             Called as C.
69              
70             This routine is optional; it is called when your plugin is loaded
71             by C. You can use this to parameterize
72             your plugin via arguments on the C statement.
73              
74             It's recommended that you supply arguments as key-value pairs;
75             this will make it possible for C
76             to remove the "used-up" parameters from the c line by
77             returning the keys you want to have removed.
78              
79             Here's a sample C method:
80              
81             sub import {
82             my($class, %args) = @_;
83             if defined(my $value = $args{'mine'}) {
84             if (_is_appropriate($value)) {
85             # do whatever ,,,
86             }
87             }
88             return ("mine");
89             }
90              
91             This looks for the C parameter on the C.
92             It processes it as appropriate and returns the
93             key so that C will delete it.
94              
95             =head2 init
96              
97             Called as C.
98              
99             The C method allows your plugin a chance to export
100             subroutines and store information appropriate for its
101             proper functioning in the parent C
102             object. It also can be used to set up pre-hooks and
103             post-hooks for methods.
104              
105             =over 4
106              
107             Note that at present it isn't possible to add hooks for
108             methods installed by other plugins; a future release of
109             this software may be able to do this.
110              
111             =back
112              
113             Because other plugins will be doing the same thing, it's
114             important to choose unique method names and field names.
115             It's proabably a good idea to prefix field names with the
116             name of your plugin, like C<_MyPlugin_data>.
117              
118             It's possible that we may change the interface in a future
119             release of C to support
120             "inside-out" objects (see http://www.windley.com/archives/2005/08/best_practices.shtml
121             for an example).
122              
123             Sample init function:
124              
125             sub init {
126             my($parent_object, %args) = @_;
127             $parent_object->{_myplugin_foo} = "my data";
128             *{caller() . '::myplugin_method'} = \&my_implementation;
129             $parent_object->pre_hook('get', sub { &my_prehook(@_) } );
130             $parent_object->post_hook('get', sub { &my_prehook(@_) } );
131             my @removed;
132             if ($args{'my_arg'}) {
133             # process my_arg
134             push @removes, 'my_arg';
135             }
136             @removed;
137             }
138              
139             The anonymous subroutine wrapping the hook setup currently is
140             necessary to prevent the hook from being called during its
141             installation; this needs to be fixed. The anonymous subroutine
142             works for the moment, and will work in future releases, so
143             go head and use it for now.
144              
145             Also note that we have the same kind of interface that we do
146             in C; you can parameterize a particular plugin by
147             putting the parameters (key=>value-style) on the C
148             and then processing them in C, and deleting them
149             after processing by returning the list of names.
150              
151             =head2 pre_hook
152              
153             Called as C<$parent_object->pre_hook('method_name", $subref)>.
154              
155             Installs the referenced subroutine as a pre-hook for the
156             named method. Currently, only C methods can
157             be hooked; future releases may allow methods supplied by plugins
158             to be hooked as well.
159              
160             =head2 post_hook
161              
162             Called as C<$parent_object->pre_hook('method_name", $subref)>.
163              
164             Installs the referenced subroutine as a post-hook for the
165             named method. Currently, only C methods can
166             be hooked; future releases may allow methods supplied by plugins
167             to be hooked as well.
168              
169             =head1 YOUR CODE
170              
171             Since pre-hooks and post-hooks are all about getting your
172             code involved in things, this section details how all that
173             works.
174              
175             =head2 Prehooks and posthooks
176              
177             Called as C.
178              
179             This is the subroutine that you passed a reference to in
180             the call to either C or C. It can do
181             anything you like; it has access to both the
182             \C object and to the
183             internal C object, as well as to the
184             parameters with which the method was called.
185              
186             If your code is a pre-hook, it can cause
187             C to skip the method
188             call altogether by returning a true value.
189              
190             Sample pre-hook:
191              
192             sub my_prehook {
193             my($pluggable, $mech, @args) = @_;
194            
195             # We'll assume that this is a hook for 'get'.
196             if ($args[0] =~ /$selected_url/) {
197              
198             # alter the URL to what we want
199             $args[0] =~ s/$what_we_dont_want/$what_we_do/;
200             }
201             # force another try with the altered URL.
202             $pluggable->get(@args);
203              
204             # don't actually do the get with the old URL.
205             return 'skip';
206             }
207              
208             We used this approach because the interface currently doesn't
209             allow us to alter the parameter list; this is something we
210             probably should do in the next release.
211              
212             =head1 RECIPIES
213              
214             =head2 Adding a new acessor
215              
216             To avoid doing a lot extra monkey coding, C is highly recommended.
217              
218             package WWW::Mechanize::Plugin::MyPlugin;
219             use base qw(Class::Accessor::Fast);
220             __PACKAGE__->mk_accessors(qw(foo bar baz));
221              
222             You can now use the newly-created accessors any way you like; often
223             you'll use them to store data for other methods that are exported to
224             C.
225              
226             =head2 Adding a new method
227              
228             This is done (for the moment) by using a construct like this:
229              
230             *{caller() . '::new_method'} = \&localsub;
231              
232             This would call any subroutine or method call to new_method
233             via the Mech::Pluggable object to be dispatched to localsub
234             in this package.
235              
236             =head2 Replacing a method
237              
238             In init, install a pre_hook for the method which does
239             something like this:
240              
241             sub init {
242             pre_hook('desired_method', sub { \&substitute(@_) });
243              
244             sub substitute {
245             my($pluggable, $mech, @_) = @_;
246             # Do whatever you want;
247             return "skip";
248             }
249              
250             Note the anonymous sub construct in the call to pre_hook.
251             This is necessary because the construct C<\&substitute>
252             tries to call substitute() immediately, which we do
253             I want.
254              
255             We return "skip" as a mnemonic that a true value causes
256             the real call to be skipped.
257              
258             =head2 Retrying a method call
259              
260             This is done with a prehook to count how many times
261             we've tried to retry an action, and a posthook to
262              
263             =over 4
264              
265             =item * take whatever action is needed to set up for the retry
266              
267             =item * call back() on the Mech object
268              
269             =item * repeat the last action again on the Mech object
270              
271             =item * up the count of tries
272              
273             =back
274              
275             The prehook is needed to keep the retry from going into
276             an infinite loop.
277              
278             =head1 CREDITS
279              
280             The Perl Advent Calendar (http://www.perladvent.org/2004/6th/) for bringing Module::Pluggable to my attention.
281              
282             Damian Conway, for showing us how to do things that Just Work.
283              
284             Andy Lester, for WWW::Mechanize.
285              
286             =cut
287              
288 11     11   22508 use strict; # or get dinged by CPANTS
  11         121  
  11         506  
289              
290             "It's only documentation but I like it";