File Coverage

blib/lib/Router/Resource.pm
Criterion Covered Total %
statement 56 56 100.0
branch 11 12 91.6
condition 5 8 62.5
subroutine 21 21 100.0
pod 8 14 57.1
total 101 111 90.9


line stmt bran cond sub pod time code
1 1     1   393 use 5.008001; use strict; use warnings;
  1     1   3  
  1     1   4  
  1         2  
  1         16  
  1         3  
  1         1  
  1         52  
2              
3             package Router::Resource;
4              
5             our $VERSION = '0.22';
6              
7 1     1   415 use Router::Simple::Route;
  1         2279  
  1         45  
8 1         7 use Sub::Exporter -setup => {
9             exports => [ qw(router resource missing GET POST PUT DELETE HEAD OPTIONS TRACE CONNECT PATCH)],
10             groups => { default => [ qw(resource router missing GET POST PUT DELETE HEAD OPTIONS TRACE CONNECT PATCH) ] }
11 1     1   569 };
  1         12896  
12              
13             sub new {
14 3     3 0 5 my $class = shift;
15 3         10 bless { @_, routes => [] };
16             }
17              
18             our (%METHS, $ROUTER);
19              
20             sub router(&;@) {
21 3     3 0 3088 my ($block, @settings) = @_;
22 3         9 local $ROUTER = __PACKAGE__->new(@settings);
23 3         8 $block->();
24 3         123 return $ROUTER;
25             }
26              
27             sub resource ($&) {
28 5     5 0 146 my ($path, $code) = @_;
29 5         6 local %METHS = ();
30 5         12 $code->();
31              
32             # Let HEAD use GET if not specified.
33 5   66     23 $METHS{HEAD} ||= $METHS{GET};
34              
35             # Add OPTIONS if requested.
36 5 100 66     15 if ($ROUTER->{auto_options} && !$METHS{OPTIONS}) {
37 1         7 my $methods = join(', ' => 'OPTIONS', keys %METHS);
38 1     1   4 $METHS{OPTIONS} = sub { [200, ['Allow', $methods], []] };
  1         8  
39             }
40              
41             # Add the route.
42 5         8 push @{ $ROUTER->{routes} }, Router::Simple::Route->new(
  5         30  
43             $path, { meths => { %METHS } }
44             );
45             }
46              
47 1     1 0 53 sub missing(&) { $ROUTER->{missing} = shift }
48 6     6 1 31 sub GET(&) { $METHS{GET} = shift }
49 1     1 1 5 sub HEAD(&) { $METHS{HEAD} = shift }
50 2     2 1 11 sub POST(&) { $METHS{POST} = shift }
51 2     2 1 10 sub PUT(&) { $METHS{PUT} = shift }
52 1     1   6 sub DELETE(&) { $METHS{DELETE} = shift }
53 1     1 1 5 sub OPTIONS(&) { $METHS{OPTIONS} = shift }
54 1     1 1 6 sub TRACE(&) { $METHS{TRACE} = shift }
55 1     1 1 6 sub CONNECT(&) { $METHS{CONNECT} = shift }
56 1     1 1 5 sub PATCH(&) { $METHS{PATCH} = shift }
57              
58             sub dispatch {
59 20     20 0 10824 my ($self, $env) = @_;
60 20         39 my $match = $self->match($env);
61 20 100       42 if (my $meth = $match->{meth}) {
62 15         52 return $meth->($env, $match->{data});
63             }
64             my $missing = $self->{missing} or return [
65 5 100       32 $match->{code}, $match->{headers}, [$match->{message}]
66             ];
67 2         4 return $missing->($env, $match);
68             }
69              
70             sub match {
71 23     23 0 1705 my ($self, $env) = @_;
72 23 50 50     71 my $meth = uc($env->{REQUEST_METHOD} || '') or return;
73              
74 23         31 for my $route (@{ $self->{routes} }) {
  23         41  
75 48 100       274 my $match = $route->match($env) or next;
76 20         533 my $meths = delete $match->{meths};
77             my $code = $meths->{$meth} or return {
78             code => 405,
79             message => 'not allowed',
80 20 100       41 headers => [Allow => join ', ', sort keys %{ $meths } ],
  4         32  
81             };
82 16         44 return { meth => $code, code => 200, data => $match };
83             }
84 3         42 return { code => 404, message => 'not found', headers => [] };
85             }
86              
87             1;
88              
89             __END__