File Coverage

blib/lib/App/Info/Handler.pm
Criterion Covered Total %
statement 9 17 52.9
branch 1 6 16.7
condition 0 8 0.0
subroutine 3 5 60.0
pod 3 3 100.0
total 16 39 41.0


line stmt bran cond sub pod time code
1             package App::Info::Handler;
2              
3             # $Id: Handler.pm 3154 2006-09-16 00:01:20Z theory $
4              
5             =head1 NAME
6            
7             App::Info::Handler - App::Info event handler base class
8            
9             =head1 SYNOPSIS
10            
11             use App::Info::Category::FooApp;
12             use App::Info::Handler;
13            
14             my $app = App::Info::Category::FooApp->new( on_info => ['default'] );
15            
16             =head1 DESCRIPTION
17            
18             This class defines the interface for subclasses that wish to handle events
19             triggered by App::Info concrete subclasses. The different types of events
20             triggered by App::Info can all be handled by App::Info::Handler (indeed, by
21             default they're all handled by a single App::Info::Handler object), and
22             App::Info::Handler subclasses may be designed to handle whatever events they
23             wish.
24            
25             If you're interested in I<using> an App::Info event handler, this is probably
26             not the class you should look at, since all it does is define a simple handler
27             that does nothing with an event. Look to the L<App::Info::Handler
28             subclasses|"SEE ALSO"> included in this distribution to do more interesting
29             things with App::Info events.
30            
31             If, on the other hand, you're interested in implementing your own event
32             handlers, read on!
33            
34             =cut
35              
36 2     2   26 use strict;
  2         18  
  2         27  
37 2     2   29 use vars qw($VERSION);
  2         19  
  2         28  
38             $VERSION = '0.51';
39              
40             my %handlers;
41              
42             =head1 INTERFACE
43            
44             This section documents the public interface of App::Info::Handler.
45            
46             =head2 Class Method
47            
48             =head3 register_handler
49            
50             App::Info::Handler->register_handler( $key => $code_ref );
51            
52             This class method may be used by App::Info::Handler subclasses to register
53             themselves with App::Info::Handler. Multiple registrations are supported. The
54             idea is that a subclass can define different functionality by specifying
55             different strings that represent different modes of constructing an
56             App::Info::Handler subclass object. The keys are case-sensitve, and should be
57             unique across App::Info::Handler subclasses so that many subclasses can be
58             loaded and used separately. If the C<$key> is already registered,
59             C<register_handler()> will throw an exception. The values are code references
60             that, when executed, return the appropriate App::Info::Handler subclass
61             object.
62            
63             =cut
64              
65             sub register_handler {
66 2     2 1 23     my ($pkg, $key, $code) = @_;
67 2 50       26     Carp::croak("Handler '$key' already exists")
68                   if $handlers{$key};
69 2         27     $handlers{$key} = $code;
70             }
71              
72             # Register ourself.
73             __PACKAGE__->register_handler('default', sub { __PACKAGE__->new } );
74              
75             ##############################################################################
76              
77             =head2 Constructor
78            
79             =head3 new
80            
81             my $handler = App::Info::Handler->new;
82             $handler = App::Info::Handler->new( key => $key);
83            
84             Constructs an App::Info::Handler object and returns it. If the key parameter
85             is provided and has been registered by an App::Info::Handler subclass via the
86             C<register_handler()> class method, then the relevant code reference will be
87             executed and the resulting App::Info::Handler subclass object returned. This
88             approach provides a handy shortcut for having C<new()> behave as an abstract
89             factory method, returning an object of the subclass appropriate to the key
90             parameter.
91            
92             =cut
93              
94             sub new {
95 0     0 1       my ($pkg, %p) = @_;
96 0   0           my $class = ref $pkg || $pkg;
97 0   0           $p{key} ||= 'default';
98 0 0 0           if ($class eq __PACKAGE__ && $p{key} ne 'default') {
99             # We were called directly! Handle it.
100 0 0                 Carp::croak("No such handler '$p{key}'") unless $handlers{$p{key}};
101 0                   return $handlers{$p{key}}->();
102                 } else {
103             # A subclass called us -- just instantiate and return.
104 0                   return bless \%p, $class;
105                 }
106             }
107              
108             =head2 Instance Method
109            
110             =head3 handler
111            
112             $handler->handler($req);
113            
114             App::Info::Handler defines a single instance method that must be defined by
115             its subclasses, C<handler()>. This is the method that will be executed by an
116             event triggered by an App::Info concrete subclass. It takes as its single
117             argument an App::Info::Request object, and returns a true value if it has
118             handled the event request. Returning a false value declines the request, and
119             App::Info will then move on to the next handler in the chain.
120            
121             The C<handler()> method implemented in App::Info::Handler itself does nothing
122             more than return a true value. It thus acts as a very simple default event
123             handler. See the App::Info::Handler subclasses for more interesting handling
124             of events, or create your own!
125            
126             =cut
127              
128 0     0 1   sub handler { 1 }
129              
130             1;
131             __END__
132            
133             =head1 SUBCLASSING
134            
135             I hatched the idea of the App::Info event model with its subclassable handlers
136             as a way of separating the aggregation of application metadata from writing a
137             user interface for handling certain conditions. I felt it a better idea to
138             allow people to create their own user interfaces, and instead to provide only
139             a few examples. The App::Info::Handler class defines the API interface for
140             handling these conditions, which App::Info refers to as "events".
141            
142             There are various types of events defined by App::Info ("info", "error",
143             "unknown", and "confirm"), but the App::Info::Handler interface is designed to
144             be flexible enough to handle any and all of them. If you're interested in
145             creating your own App::Info event handler, this is the place to learn how.
146            
147             =head2 The Interface
148            
149             To create an App::Info event handler, all one need do is subclass
150             App::Info::Handler and then implement the C<new()> constructor and the
151             C<handler()> method. The C<new()> constructor can do anything you like, and
152             take any arguments you like. However, I do recommend that the first thing
153             you do in your implementation is to call the super constructor:
154            
155             sub new {
156             my $pkg = shift;
157             my $self = $pkg->SUPER::new(@_);
158             # ... other stuff.
159             return $self;
160             }
161            
162             Although the default C<new()> constructor currently doesn't do much, that may
163             change in the future, so this call will keep you covered. What it does do is
164             take the parameterized arguments and assign them to the App::Info::Handler
165             object. Thus if you've specified a "mode" argument, where clients can
166             construct objects of you class like this:
167            
168             my $handler = FooHandler->new( mode => 'foo' );
169            
170             You can access the mode parameter directly from the object, like so:
171            
172             sub new {
173             my $pkg = shift;
174             my $self = $pkg->SUPER::new(@_);
175             if ($self->{mode} eq 'foo') {
176             # ...
177             }
178             return $self;
179             }
180            
181             Just be sure not to use a parameter key name required by App::Info::Handler
182             itself. At the moment, the only parameter accepted by App::Info::Handler is
183             "key", so in general you'll be pretty safe.
184            
185             Next, I recommend that you take advantage of the C<register_handler()> method
186             to create some shortcuts for creating handlers of your class. For example, say
187             we're creating a handler subclass FooHandler. It has two modes, a default
188             "foo" mode and an advanced "bar" mode. To allow both to be constructed by
189             stringified shortcuts, the FooHandler class implementation might start like
190             this:
191            
192             package FooHandler;
193            
194             use strict;
195             use App::Info::Handler;
196             use vars qw(@ISA);
197             @ISA = qw(App::Info::Handler);
198            
199             foreach my $c (qw(foo bar)) {
200             App::Info::Handler->register_handler
201             ( $c => sub { __PACKAGE__->new( mode => $c) } );
202             }
203            
204             The strings "foo" and "bar" can then be used by clients as shortcuts to have
205             App::Info objects automatically create and use handlers for certain events.
206             For example, if a client wanted to use a "bar" event handler for its info
207             events, it might do this:
208            
209             use App::Info::Category::FooApp;
210             use FooHandler;
211            
212             my $app = App::Info::Category::FooApp->new(on_info => ['bar']);
213            
214             Take a look at App::Info::Handler::Print and App::Info::Handler::Carp to see
215             concrete examples of C<register_handler()> usage.
216            
217             The final step in creating a new App::Info event handler is to implement the
218             C<handler()> method itself. This method takes a single argument, an
219             App::Info::Request object, and is expected to return true if it handled the
220             request, and false if it did not. The App::Info::Request object contains all
221             the metadata relevant to a request, including the type of event that triggered
222             it; see L<App::Info::Request|App::Info::Request> for its documentation.
223            
224             Use the App::Info::Request object however you like to handle the request
225             however you like. You are, however, expected to abide by a a few guidelines:
226            
227             =over 4
228            
229             =item *
230            
231             For error and info events, you are expected (but not required) to somehow
232             display the info or error message for the user. How your handler chooses to do
233             so is up to you and the handler.
234            
235             =item *
236            
237             For unknown and confirm events, you are expected to prompt the user for a
238             value. If it's a confirm event, offer the known value (found in
239             C<$req-E<gt>value>) as a default.
240            
241             =item *
242            
243             For unknown and confirm events, you are expected to call C<$req-E<gt>callback>
244             and pass in the new value. If C<$req-E<gt>callback> returns a false value, you
245             are expected to display the error message in C<$req-E<gt>error> and prompt the
246             user again. Note that C<$req-E<gt>value> calls C<$req-E<gt>callback>
247             internally, and thus assigns the value and returns true if
248             C<$req-E<gt>callback> returns true, and does not assign the value and returns
249             false if C<$req-E<gt>callback> returns false.
250            
251             =item *
252            
253             For unknown and confirm events, if you've collected a new value and
254             C<$req-E<gt>callback> returns true for that value, you are expected to assign
255             the value by passing it to C<$req-E<gt>value>. This allows App::Info to give
256             the value back to the calling App::Info concrete subclass.
257            
258             =back
259            
260             Probably the easiest way to get started creating new App::Info event handlers
261             is to check out the simple handlers provided with the distribution and follow
262             their logical examples. Consult the App::Info documentation of the L<event
263             methods|App::Info/"Events"> for details on how App::Info constructs the
264             App::Info::Request object for each event type.
265            
266             =head1 BUGS
267            
268             Please send bug reports to <bug-app-info@rt.cpan.org> or file them at
269             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Info>.
270            
271             =head1 AUTHOR
272            
273             David Wheeler <david@justatheory.com>
274            
275             =head1 SEE ALSO
276            
277             L<App::Info|App::Info> thoroughly documents the client interface for setting
278             event handlers, as well as the event triggering interface for App::Info
279             concrete subclasses.
280            
281             L<App::Info::Request|App::Info::Request> documents the interface for the
282             request objects passed to App::Info::Handler C<handler()> methods.
283            
284             The following App::Info::Handler subclasses offer examples for event handler
285             authors, and, of course, provide actual event handling functionality for
286             App::Info clients.
287            
288             =over 4
289            
290             =item L<App::Info::Handler::Carp|App::Info::Handler::Carp>
291            
292             =item L<App::Info::Handler::Print|App::Info::Handler::Print>
293            
294             =item L<App::Info::Handler::Prompt|App::Info::Handler::Prompt>
295            
296             =back
297            
298             =head1 COPYRIGHT AND LICENSE
299            
300             Copyright (c) 2002-2006, David Wheeler. All Rights Reserved.
301            
302             This module is free software; you can redistribute it and/or modify it under the
303             same terms as Perl itself.
304            
305             =cut
306