make bump
[catagits/Web-Simple.git] / lib / Web / Simple.pm
1 package Web::Simple;
2
3 use strictures 1;
4 use warnings::illegalproto ();
5 use Moo ();
6 use Web::Dispatch::Wrapper ();
7
8 our $VERSION = '0.028';
9
10 sub import {
11   my ($class, $app_package) = @_;
12   $app_package ||= caller;
13   $class->_export_into($app_package);
14   eval "package $app_package; use Web::Dispatch::Wrapper; use Moo; 1"
15     or die "Failed to setup app package: $@";
16   strictures->import;
17   warnings::illegalproto->unimport;
18 }
19
20 sub _export_into {
21   my ($class, $app_package) = @_;
22   {
23     no strict 'refs';
24     *{"${app_package}::PSGI_ENV"} = sub () { -1 };
25     require Web::Simple::Application;
26     unshift(@{"${app_package}::ISA"}, 'Web::Simple::Application');
27   }
28   (my $name = $app_package) =~ s/::/\//g;
29   $INC{"${name}.pm"} = 'Set by "use Web::Simple;" invocation';
30 }
31
32 1;
33
34 =head1 NAME
35
36 Web::Simple - A quick and easy way to build simple web applications
37
38
39 =head1 SYNOPSIS
40
41   #!/usr/bin/env perl
42
43   package HelloWorld;
44   use Web::Simple;
45
46   sub dispatch_request {
47     sub (GET) {
48       [ 200, [ 'Content-type', 'text/plain' ], [ 'Hello world!' ] ]
49     },
50     sub () {
51       [ 405, [ 'Content-type', 'text/plain' ], [ 'Method not allowed' ] ]
52     }
53   }
54
55   HelloWorld->run_if_script;
56
57 If you save this file into your cgi-bin as C<hello-world.cgi> and then visit:
58
59   http://my.server.name/cgi-bin/hello-world.cgi/
60
61 you'll get the "Hello world!" string output to your browser. At the same time
62 this file will also act as a class module, so you can save it as HelloWorld.pm
63 and use it as-is in test scripts or other deployment mechanisms.
64
65 Note that you should retain the ->run_if_script even if your app is a
66 module, since this additionally makes it valid as a .psgi file, which can
67 be extremely useful during development.
68
69 For more complex examples and non-CGI deployment, see
70 L<Web::Simple::Deployment>. To get help with L<Web::Simple>, please connect to
71 the irc.perl.org IRC network and join #web-simple.
72
73 =head1 DESCRIPTION
74
75 The philosophy of L<Web::Simple> is to keep to an absolute bare minimum for
76 everything. It is not designed to be used for large scale applications;
77 the L<Catalyst> web framework already works very nicely for that and is
78 a far more mature, well supported piece of software.
79
80 However, if you have an application that only does a couple of things, and
81 want to not have to think about complexities of deployment, then L<Web::Simple>
82 might be just the thing for you.
83
84 The only public interface the L<Web::Simple> module itself provides is an
85 C<import> based one:
86
87   use Web::Simple 'NameOfApplication';
88
89 This sets up your package (in this case "NameOfApplication" is your package)
90 so that it inherits from L<Web::Simple::Application> and imports L<strictures>,
91 as well as installs a C<PSGI_ENV> constant for convenience, as well as some
92 other subroutines.
93
94 Importing L<strictures> will automatically make your code use the C<strict> and
95 C<warnings> pragma, so you can skip the usual:
96
97   use strict;
98   use warnings FATAL => 'aa';
99
100 provided you 'use Web::Simple' at the top of the file. Note that we turn
101 on *fatal* warnings so if you have any warnings at any point from the file
102 that you did 'use Web::Simple' in, then your application will die. This is,
103 so far, considered a feature.
104
105 When we inherit from L<Web::Simple::Application> we also use L<Moo>, which is
106 the the equivalent of:
107
108   {
109     package NameOfApplication;
110     use Moo;
111     extends 'Web::Simple::Application';
112   }
113
114 So you can use L<Moo> features in your application, such as creating attributes
115 using the C<has> subroutine, etc.  Please see the documentation for L<Moo> for
116 more information.
117
118 It also exports the following subroutines for use in dispatchers:
119
120   response_filter { ... };
121
122   redispatch_to '/somewhere';
123
124 Finally, import sets
125
126   $INC{"NameOfApplication.pm"} = 'Set by "use Web::Simple;" invocation';
127
128 so that perl will not attempt to load the application again even if
129
130   require NameOfApplication;
131
132 is encountered in other code.
133
134 One important thing to remember when using
135
136   NameOfApplication->run_if_script;
137
138 At the end of your app is that this call will create an instance of your app
139 for you automatically, regardless of context. An easier way to think of this
140 would be if the method were more verbosely named
141
142  NameOfApplication->run_request_if_script_else_turn_coderef_for_psgi;
143
144 =head1 DISPATCH STRATEGY
145
146 L<Web::Simple> despite being straightforward to use, has a powerful system
147 for matching all sorts of incoming URLs to one or more subroutines.  These
148 subroutines can be simple actions to take for a given URL, or something
149 more complicated, including entire L<Plack> applications, L<Plack::Middleware>
150 and nested subdispatchers.
151
152 =head2 Examples
153
154  sub dispatch_request {
155    # matches: GET /user/1.htm?show_details=1
156    #          GET /user/1.htm
157    sub (GET + /user/* + ?show_details~ + .htm|.html|.xhtml) {
158      my ($self, $user_id, $show_details) = @_;
159      ...
160    },
161    # matches: POST /user?username=frew
162    #          POST /user?username=mst&first_name=matt&last_name=trout
163    sub (POST + /user + ?username=&*) {
164       my ($self, $username, $misc_params) = @_;
165      ...
166    },
167    # matches: DELETE /user/1/friend/2
168    sub (DELETE + /user/*/friend/*) {
169      my ($self, $user_id, $friend_id) = @_;
170      ...
171    },
172    # matches: PUT /user/1?first_name=Matt&last_name=Trout
173    sub (PUT + /user/* + ?first_name~&last_name~) {
174      my ($self, $user_id, $first_name, $last_name) = @_;
175      ...
176    },
177    sub (/user/*/...) {
178      my $user_id = $_[1];
179      # matches: PUT /user/1/role/1
180      sub (PUT + /role/*) {
181        my $role_id = $_[1];
182        ...
183      },
184      # matches: DELETE /user/1/role/1
185      sub (DELETE + /role/*) {
186        my $role_id = $_[1];
187        ...
188      },
189    },
190  }
191
192 =head2 The dispatch cycle
193
194 At the beginning of a request, your app's dispatch_request method is called
195 with the PSGI $env as an argument. You can handle the request entirely in
196 here and return a PSGI response arrayref if you want:
197
198   sub dispatch_request {
199     my ($self, $env) = @_;
200     [ 404, [ 'Content-type' => 'text/plain' ], [ 'Amnesia == fail' ] ]
201   }
202
203 However, generally, instead of that, you return a set of dispatch subs:
204
205   sub dispatch_request {
206     my $self = shift;
207     sub (/) { redispatch_to '/index.html' },
208     sub (/user/*) { $self->show_user($_[1]) },
209     ...
210   }
211
212 Well, a sub is a valid PSGI response too (for ultimate streaming and async
213 cleverness). If you want to return a PSGI sub you have to wrap it into an
214 array ref.
215
216   sub dispatch_request {
217     [ sub {
218         my $respond = shift;
219         # This is pure PSGI here, so read perldoc PSGI
220     } ]
221   }
222
223 If you return a subroutine with a prototype, the prototype is treated
224 as a match specification - and if the test is passed, the body of the
225 sub is called as a method and passed any matched arguments (see below for more details).
226
227 You can also return a plain subroutine which will be called with just C<$env>
228 - remember that in this case if you need C<$self> you B<must> close over it.
229
230 If you return a normal object, L<Web::Simple> will simply return it upwards on
231 the assumption that a response_filter (or some arbitrary L<Plack::Middleware>)
232 somewhere will convert it to something useful.  This allows:
233
234   sub dispatch_request {
235     my $self = shift;
236     sub (.html) { response_filter { $self->render_zoom($_[0]) } },
237     sub (/user/*) { $self->users->get($_[1]) },
238   }
239
240 An alternative to using prototypes to declare a match specification for a given
241 route is to provide a Dancer like key-value list:
242
243   sub dispatch_request {
244     my $self = shift;
245     (
246       '.html' => sub { response_filter { $self->render_zoom($_[0]) } },
247       '/user/*' => sub { $self->users->get($_[1]) },
248       'POST + %*' => 'handle_post',
249     )
250   }
251
252 This can be useful in situations where you are generating a dispatch table
253 programmatically, where setting a subroutines protoype is difficult.  Note that
254 in the example above, C<handle_post> is a method that would be called.
255
256 to render a user object to HTML, if there is an incoming URL such as:
257
258   http://myweb.org/user/111.html
259
260 This works because as we descend down the dispachers, we first match
261 C<sub (.html)>, which adds a C<response_filter> (basically a specialized routine
262 that follows the L<Plack::Middleware> specification), and then later we also
263 match C<sub (/user/*)> which gets a user and returns that as the response.
264 This user object 'bubbles up' through all the wrapping middleware until it hits
265 the C<response_filter> we defined, after which the return is converted to a
266 true html response.
267
268 However, two types of objects are treated specially - a C<Plack::Component> object
269 will have its C<to_app> method called and be used as a dispatcher:
270
271   sub dispatch_request {
272     my $self = shift;
273     sub (/static/...) { Plack::App::File->new(...) },
274     ...
275   }
276
277 A L<Plack::Middleware> object will be used as a filter for the rest of the
278 dispatch being returned into:
279
280   ## responds to /admin/track_usage AND /admin/delete_accounts
281
282   sub dispatch_request {
283     my $self = shift;
284     sub (/admin/**) {
285       Plack::Middleware::Session->new(%opts);
286     },
287     sub (/admin/track_usage) {
288       ## something that needs a session
289     },
290     sub (/admin/delete_accounts) {
291       ## something else that needs a session
292     },
293   }
294
295 Note that this is for the dispatch being B<returned> to, so if you want to
296 provide it inline you need to do:
297
298   ## ALSO responds to /admin/track_usage AND /admin/delete_accounts
299
300   sub dispatch_request {
301     my $self = shift;
302     sub (/admin/...) {
303       sub {
304         Plack::Middleware::Session->new(%opts);
305       },
306       sub (/track_usage) {
307         ## something that needs a session
308       },
309       sub (/delete_accounts) {
310         ## something else that needs a session
311       },
312     }
313   }
314
315 And that's it - but remember that all this happens recursively - it's
316 dispatchers all the way down.  A URL incoming pattern will run all matching
317 dispatchers and then hit all added filters or L<Plack::Middleware>.
318
319 =head2 Web::Simple match specifications
320
321 =head3 Method matches
322
323   sub (GET) {
324
325 A match specification beginning with a capital letter matches HTTP requests
326 with that request method.
327
328 =head3 Path matches
329
330   sub (/login) {
331
332 A match specification beginning with a / is a path match. In the simplest
333 case it matches a specific path. To match a path with a wildcard part, you
334 can do:
335
336   sub (/user/*) {
337     $self->handle_user($_[1])
338
339 This will match /user/<anything> where <anything> does not include a literal
340 / character. The matched part becomes part of the match arguments. You can
341 also match more than one part:
342
343   sub (/user/*/*) {
344     my ($self, $user_1, $user_2) = @_;
345
346   sub (/domain/*/user/*) {
347     my ($self, $domain, $user) = @_;
348
349 and so on. To match an arbitrary number of parts, use C<**>:
350
351   sub (/page/**) {
352     my ($self, $match) = @_;
353
354 This will result in a single element for the entire match. Note that you can do
355
356   sub (/page/**/edit) {
357
358 to match an arbitrary number of parts up to but not including some final
359 part.
360
361 Note: Since Web::Simple handles a concept of file extensions, C<*> and C<**>
362 matchers will not by default match things after a final dot, and this
363 can be modified by using C<*.*> and C<**.*> in the final position, e.g.:
364
365   /one/*       matches /one/two.three    and captures "two"
366   /one/*.*     matches /one/two.three    and captures "two.three"
367   /**          matches /one/two.three    and captures "one/two"
368   /**.*        matches /one/two.three    and captures "one/two.three"
369
370 Finally,
371
372   sub (/foo/...) {
373
374 Will match C</foo/> on the beginning of the path B<and> strip it. This is
375 designed to be used to construct nested dispatch structures, but can also prove
376 useful for having e.g. an optional language specification at the start of a
377 path.
378
379 Note that the '...' is a "maybe something here, maybe not" so the above
380 specification will match like this:
381
382   /foo         # no match
383   /foo/        # match and strip path to '/'
384   /foo/bar/baz # match and strip path to '/bar/baz'
385
386 Almost the same,
387
388   sub (/foo...) {
389
390 Will match on C</foo/bar/baz>, but also include C</foo>.  Otherwise it
391 operates the same way as C</foo/...>.
392
393   /foo         # match and strip path to ''
394   /foo/        # match and strip path to '/'
395   /foo/bar/baz # match and strip path to '/bar/baz'
396
397 Please note the difference between C<sub(/foo/...)> and C<sub(/foo...)>.  In
398 the first case, this is expecting to find something after C</foo> (and fails to
399 match if nothing is found), while in the second case we can match both C</foo>
400 and C</foo/more/to/come>.  The following are roughly the same:
401
402   sub (/foo)   { 'I match /foo' },
403   sub (/foo/...) {
404     sub (/bar) { 'I match /foo/bar' },
405     sub (/*)   { 'I match /foo/{id}' },
406   }
407
408 Versus
409
410   sub (/foo...) {
411     sub (~)    { 'I match /foo' },
412     sub (/bar) { 'I match /foo/bar' },
413     sub (/*)   { 'I match /foo/{id}' },
414   }
415
416 You may prefer the latter example should you wish to take advantage of
417 subdispatchers to scope common activities.  For example:
418
419   sub (/user...) {
420     my $user_rs = $schema->resultset('User');
421     sub (~) { $user_rs },
422     sub (/*) { $user_rs->find($_[1]) },
423   }
424
425 You should note the special case path match C<sub (~)> which is only meaningful
426 when it is contained in this type of path match. It matches to an empty path.
427
428 =head4 Naming your patch matches
429
430 Any C<*>, C<**>, C<*.*>, or C<**.*> match can be followed with C<:name> to make it into a named
431 match, so:
432
433   sub (/*:one/*:two/*:three/*:four) {
434     "I match /1/2/3/4 capturing { one => 1, two =>  2, three => 3, four => 4 }"
435   }
436   
437   sub (/**.*:allofit) {
438     "I match anything capturing { allofit => \$whole_path }"
439   }
440
441 In the specific case of a simple single-* match, the * may be omitted, to
442 allow you to write:
443
444   sub (/:one/:two/:three/:four) {
445     "I match /1/2/3/4 capturing { one => 1, two =>  2, three => 3, four => 4 }"
446   }
447
448 =head4 C</foo> and C</foo/> are different specs
449
450 As you may have noticed with the difference between C<sub(/foo/...)> and
451 C<sub(/foo...)>, trailing slashes in path specs are significant. This is
452 intentional and necessary to retain the ability to use relative links on
453 websites. Let's demonstrate on this link:
454
455   <a href="bar">bar</a>
456
457 If the user loads the url C</foo/> and clicks on this link, they will be
458 sent to C</foo/bar>. However when they are on the url C</foo> and click this
459 link, then they will be sent to C</bar>.
460
461 This makes it necessary to be explicit about the trailing slash.
462
463 =head3 Extension matches
464
465   sub (.html) {
466
467 will match .html from the path (assuming the subroutine itself returns
468 something, of course). This is normally used for rendering - e.g.:
469
470   sub (.html) {
471     response_filter { $self->render_html($_[1]) }
472   }
473
474 Additionally,
475
476   sub (.*) {
477
478 will match any extension and supplies the extension as a match argument.
479
480 =head3 Query and body parameter matches
481
482 Query and body parameters can be match via
483
484   sub (?<param spec>) { # match URI query
485   sub (%<param spec>) { # match body params
486
487 The body spec will match if the request content is either
488 application/x-www-form-urlencoded or multipart/form-data - the latter
489 of which is required for uploads - see below.
490
491 The param spec is elements of one of the following forms:
492
493   param~        # optional parameter
494   param=        # required parameter
495   @param~       # optional multiple parameter
496   @param=       # required multiple parameter
497   :param~       # optional parameter in hashref
498   :param=       # required parameter in hashref
499   :@param~      # optional multiple in hashref
500   :@param=      # required multiple in hashref
501   *             # include all other parameters in hashref
502   @*            # include all other parameters as multiple in hashref
503
504 separated by the C<&> character. The arguments added to the request are
505 one per non-C<:>/C<*> parameter (scalar for normal, arrayref for multiple),
506 plus if any C<:>/C<*> specs exist a hashref containing those values.
507
508 Please note that if you specify a multiple type parameter match, you are
509 ensured of getting an arrayref for the value, EVEN if the current incoming
510 request has only one value.  However if a parameter is specified as single
511 and multiple values are found, the last one will be used.
512
513 For example to match a C<page> parameter with an optional C<order_by> parameter one
514 would write:
515
516   sub (?page=&order_by~) {
517     my ($self, $page, $order_by) = @_;
518     return unless $page =~ /^\d+$/;
519     $order_by ||= 'id';
520     response_filter {
521       $_[1]->search_rs({}, { page => $page, order_by => $order_by });
522     }
523   }
524
525 to implement paging and ordering against a L<DBIx::Class::ResultSet> object.
526
527 Another Example: To get all parameters as a hashref of arrayrefs, write:
528
529   sub(?@*) {
530     my ($self, $params) = @_;
531     ...
532
533 To get two parameters as a hashref, write:
534
535   sub(?:user~&:domain~) {
536     my ($self, $params) = @_; # params contains only 'user' and 'domain' keys
537
538 You can also mix these, so:
539
540   sub (?foo=&@bar~&:coffee=&@*) {
541      my ($self, $foo, $bar, $params);
542
543 where $bar is an arrayref (possibly an empty one), and $params contains
544 arrayref values for all parameters B<not> mentioned and a scalar value for
545 the 'coffee' parameter.
546
547 Note, in the case where you combine arrayref, single parameter and named
548 hashref style, the arrayref and single parameters will appear in C<@_> in the
549 order you defined them in the protoype, but all hashrefs will merge into a
550 single C<$params>, as in the example above.
551
552 =head3 Upload matches
553
554   sub (*foo=) { # param specifier can be anything valid for query or body
555
556 The upload match system functions exactly like a query/body match, except
557 that the values returned (if any) are C<Web::Dispatch::Upload> objects.
558
559 Note that this match type will succeed in two circumstances where you might
560 not expect it to - first, when the field exists but is not an upload field
561 and second, when the field exists but the form is not an upload form (i.e.
562 content type "application/x-www-form-urlencoded" rather than
563 "multipart/form-data"). In either of these cases, what you'll get back is
564 a C<Web::Dispatch::NotAnUpload> object, which will C<die> with an error
565 pointing out the problem if you try and use it. To be sure you have a real
566 upload object, call
567
568   $upload->is_upload # returns 1 on a valid upload, 0 on a non-upload field
569
570 and to get the reason why such an object is not an upload, call
571
572   $upload->reason # returns a reason or '' on a valid upload.
573
574 Other than these two methods, the upload object provides the same interface
575 as L<Plack::Request::Upload> with the addition of a stringify to the temporary
576 filename to make copying it somewhere else easier to handle.
577
578 =head3 Combining matches
579
580 Matches may be combined with the + character - e.g.
581
582   sub (GET + /user/*) {
583
584 to create an AND match. They may also be combined withe the | character - e.g.
585
586   sub (GET|POST) {
587
588 to create an OR match. Matches can be nested with () - e.g.
589
590   sub ((GET|POST) + /user/*) {
591
592 and negated with ! - e.g.
593
594   sub (!/user/foo + /user/*) {
595
596 ! binds to the immediate rightmost match specification, so if you want
597 to negate a combination you will need to use
598
599   sub ( !(POST|PUT|DELETE) ) {
600
601 and | binds tighter than +, so
602
603   sub ((GET|POST) + /user/*) {
604
605 and
606
607   sub (GET|POST + /user/*) {
608
609 are equivalent, but
610
611   sub ((GET + /admin/...) | (POST + /admin/...)) {
612
613 and
614
615   sub (GET + /admin/... | POST + /admin/...) {
616
617 are not - the latter is equivalent to
618
619   sub (GET + (/admin/...|POST) + /admin/...) {
620
621 which will never match!
622
623 =head3 Whitespace
624
625 Note that for legibility you are permitted to use whitespace:
626
627   sub (GET + /user/*) {
628
629 but it will be ignored. This is because the perl parser strips whitespace
630 from subroutine prototypes, so this is equivalent to
631
632   sub (GET+/user/*) {
633
634 =head3 Accessing parameters via C<%_>
635
636 If your dispatch specification causes your dispatch subroutine to receive
637 a hash reference as its first argument, the contained named parameters
638 will be accessible via C<%_>.
639
640 This can be used to access your path matches, if they are named:
641
642   sub (GET + /foo/:path_part) {
643     [ 200,
644       ['Content-type' => 'text/plain'],
645       ["We are in $_{path_part}"],
646     ];
647   }
648
649 Or, if your first argument would be a hash reference containing named
650 query parameters:
651
652   sub (GET + /foo + ?:some_param=) {
653     [ 200,
654       ['Content-type' => 'text/plain'],
655       ["We received $_{some_param} as parameter"],
656     ];
657   }
658
659 Of course this also works when all you are doing is slurping the whole set
660 of parameters by their name:
661
662   sub (GET + /foo + ?*) {
663     [ 200,
664       ['Content-type' => 'text/plain'],
665       [exists($_{foo}) ? "Received a foo: $_{foo}" : "No foo!"],
666     ],
667   }
668
669 Note that only the first hash reference will be available via C<%_>. If
670 you receive additional hash references, you will need to access them as
671 usual.
672
673 =head3 Accessing the PSGI env hash
674
675 In some cases you may wish to get the raw PSGI env hash - to do this,
676 you can either use a plain sub:
677
678   sub {
679     my ($env) = @_;
680     ...
681   }
682
683 or use the C<PSGI_ENV> constant exported to retrieve it from C<@_>:
684
685   sub (GET + /foo + ?some_param=) {
686     my $param = $_[1];
687     my $env = $_[PSGI_ENV];
688   }
689
690 but note that if you're trying to add a middleware, you should simply use
691 Web::Simple's direct support for doing so.
692
693 =head1 EXPORTED SUBROUTINES
694
695 =head2 response_filter
696
697   response_filter {
698     # Hide errors from the user because we hates them, preciousss
699     if (ref($_[0]) eq 'ARRAY' && $_[0]->[0] == 500) {
700       $_[0] = [ 200, @{$_[0]}[1..$#{$_[0]}] ];
701     }
702     return $_[0];
703   };
704
705 The response_filter subroutine is designed for use inside dispatch subroutines.
706
707 It creates and returns a special dispatcher that always matches, and calls
708 the block passed to it as a filter on the result of running the rest of the
709 current dispatch chain.
710
711 Thus the filter above runs further dispatch as normal, but if the result of
712 dispatch is a 500 (Internal Server Error) response, changes this to a 200 (OK)
713 response without altering the headers or body.
714
715 =head2 redispatch_to
716
717   redispatch_to '/other/url';
718
719 The redispatch_to subroutine is designed for use inside dispatch subroutines.
720
721 It creates and returns a special dispatcher that always matches, and instead
722 of continuing dispatch re-delegates it to the start of the dispatch process,
723 but with the path of the request altered to the supplied URL.
724
725 Thus if you receive a POST to C</some/url> and return a redispatch to
726 C</other/url>, the dispatch behaviour will be exactly as if the same POST
727 request had been made to C</other/url> instead.
728
729 Note, this is not the same as returning an HTTP 3xx redirect as a response;
730 rather it is a much more efficient internal process.
731
732 =head1 CHANGES BETWEEN RELEASES
733
734 =head2 Changes between 0.004 and 0.005
735
736 =over 4
737
738 =item * dispatch {} replaced by declaring a dispatch_request method
739
740 dispatch {} has gone away - instead, you write:
741
742   sub dispatch_request {
743     my $self = shift;
744     sub (GET /foo/) { ... },
745     ...
746   }
747
748 Note that this method is still B<returning> the dispatch code - just like
749 C<dispatch> did.
750
751 Also note that you need the C<< my $self = shift >> since the magic $self
752 variable went away.
753
754 =item * the magic $self variable went away.
755
756 Just add C<< my $self = shift; >> while writing your C<< sub dispatch_request { >>
757 like a normal perl method.
758
759 =item * subdispatch deleted - all dispatchers can now subdispatch
760
761 In earlier releases you needed to write:
762
763   subdispatch sub (/foo/...) {
764     ...
765     [
766       sub (GET /bar/) { ... },
767       ...
768     ]
769   }
770
771 As of 0.005, you can instead write simply:
772
773   sub (/foo/...) {
774     ...
775     (
776       sub (GET /bar/) { ... },
777       ...
778     )
779   }
780
781 =back
782
783 =head2 Changes since Antiquated Perl
784
785 =over 4
786
787 =item * filter_response renamed to response_filter
788
789 This is a pure rename; a global search and replace should fix it.
790
791 =item * dispatch [] changed to dispatch {}
792
793 Simply changing
794
795   dispatch [ sub(...) { ... }, ... ];
796
797 to
798
799   dispatch { sub(...) { ... }, ... };
800
801 should work fine.
802
803 =back
804
805 =head1 DEVELOPMENT HISTORY
806
807 Web::Simple was originally written to form part of my Antiquated Perl talk for
808 Italian Perl Workshop 2009, but in writing the bloggery example I realised
809 that having a bare minimum system for writing web applications that doesn't
810 drive me insane was rather nice and decided to spend my attempt at nanowrimo
811 for 2009 improving and documenting it to the point where others could use it.
812
813 The Antiquated Perl talk can be found at L<http://www.shadowcat.co.uk/archive/conference-video/> and the slides are reproduced in this distribution under
814 L<Web::Simple::AntiquatedPerl>.
815
816 =head1 COMMUNITY AND SUPPORT
817
818 =head2 IRC channel
819
820 irc.perl.org #web-simple
821
822 =head2 No mailing list yet
823
824 Because mst's non-work email is a bombsite so he'd never read it anyway.
825
826 =head2 Git repository
827
828 Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is:
829
830   git clone git://git.shadowcat.co.uk/catagits/Web-Simple.git
831
832 =head1 AUTHOR
833
834 Matt S. Trout (mst) <mst@shadowcat.co.uk>
835
836 =head1 CONTRIBUTORS
837
838 Devin Austin (dhoss) <dhoss@cpan.org>
839
840 Arthur Axel 'fREW' Schmidt <frioux@gmail.com>
841
842 gregor herrmann (gregoa) <gregoa@debian.org>
843
844 John Napiorkowski (jnap) <jjn1056@yahoo.com>
845
846 Josh McMichael <jmcmicha@linus222.gsc.wustl.edu>
847
848 Justin Hunter (arcanez) <justin.d.hunter@gmail.com>
849
850 Kjetil Kjernsmo <kjetil@kjernsmo.net>
851
852 markie <markie@nulletch64.dreamhost.com>
853
854 Christian Walde (Mithaldu) <walde.christian@googlemail.com>
855
856 nperez <nperez@cpan.org>
857
858 Robin Edwards <robin.ge@gmail.com>
859
860 Andrew Rodland (hobbs) <andrew@cleverdomain.org>
861
862 Robert Sedlacek (phaylon) <r.sedlacek@shadowcat.co.uk>
863
864 Hakim Cassimally (osfameron) <osfameron@cpan.org>
865
866 Karen Etheridge (ether) <ether@cpan.org>
867
868 =head1 COPYRIGHT
869
870 Copyright (c) 2011 the Web::Simple L</AUTHOR> and L</CONTRIBUTORS>
871 as listed above.
872
873 =head1 LICENSE
874
875 This library is free software and may be distributed under the same terms
876 as perl itself.
877
878 =cut