File Coverage

blib/lib/Plack/Middleware/REST.pm
Criterion Covered Total %
statement 64 64 100.0
branch 27 32 84.3
condition 10 22 45.4
subroutine 9 9 100.0
pod 2 2 100.0
total 112 129 86.8


line stmt bran cond sub pod time code
1             package Plack::Middleware::REST;
2 2     2   41584 use strict;
  2         2  
  2         52  
3 2     2   7 use warnings;
  2         2  
  2         58  
4              
5             our $VERSION = '0.10';
6              
7 2     2   6 use Carp qw(croak);
  2         4  
  2         84  
8 2     2   8 use Scalar::Util qw(reftype);
  2         2  
  2         118  
9              
10 2     2   363 use parent 'Plack::Middleware';
  2         211  
  2         6  
11             use Plack::Util::Accessor
12 2     2   10104 qw(get create upsert delete list head pass_through routes options patch patch_types);
  2         3  
  2         7  
13              
14 2     2   828 use Plack::Middleware::Head;
  2         321  
  2         769  
15              
16             sub prepare_app {
17 3     3 1 1534 my ($self) = @_;
18              
19 3 50       9 $self->pass_through(0) unless defined $self->pass_through;
20 3 100       92 $self->head(1) unless defined $self->head;
21 3 100       19 $self->options(1) unless defined $self->options;
22              
23 3         42 $self->routes({
24             resource => {
25             GET => 'get',
26             PUT => 'upsert',
27             DELETE => 'delete',
28             PATCH => 'patch',
29             },
30             collection => {
31             GET => 'list',
32             POST => 'create',
33             },
34             });
35              
36 3 100       14 if ($self->head) {
37 2         15 $self->routes->{resource}->{HEAD} = 'get';
38 2         11 $self->routes->{collection}->{HEAD} = 'list';
39             }
40            
41 3 100       13 if ($self->options) {
42 2         9 $self->routes->{resource}->{OPTIONS} = 'get';
43 2         8 $self->routes->{collection}->{OPTIONS} = 'list';
44             }
45              
46 3         12 foreach my $action (qw(get create upsert delete list patch)) {
47 18         16 my $app = $self->{$action};
48              
49             # alias
50 18 50 66     41 $self->{$action} = $self->{$app} if $app and !ref $app;
51              
52 18 50 0     37 croak "PSGI application '$action' must be code reference"
      33        
53             if $self->{action} and (reftype($self->{$action}) || '') ne 'CODE';
54             }
55              
56 3         6 while (my ($type, $route) = each %{$self->routes}) {
  9         63  
57 26         45 $self->{allow}->{$type} = join ', ',
58 6         36 sort grep { $self->{ $route->{$_} } } keys %$route;
59 6         11 foreach my $method (keys %$route) {
60 26         33 $route->{$method} = $self->{ $route->{$method} };
61             }
62 6 100       13 if ($self->head eq 'auto') {
63 2         16 $route->{HEAD} = Plack::Middleware::Head->wrap($route->{HEAD});
64             }
65             }
66             }
67              
68             sub call {
69 24     24 1 53093 my ($self, $env) = @_;
70              
71 24 100 50     85 my $type = ($env->{PATH_INFO} || '/') eq '/' ? 'collection' : 'resource';
72 24         22 my $method = $env->{REQUEST_METHOD};
73              
74 24 100       33 if ($method eq 'OPTIONS') {
75 5 100       13 if ($self->options) {
76 3         23 my %headers = ( 'Allow' => $self->{allow}->{$type} );
77 3 50 33     6 if ($self->patch() && $self->patch_types()) {
78 3         29 $headers{'Accept-Patch'} = join( ',', @{$self->patch_types()} );
  3         4  
79             }
80 3         35 [ 200, [ %headers ], [] ];
81             } else {
82 2 100       24 [ 405, [ Allow => $self->{allow}->{$type} ? $self->{allow}->{$type} : 'GET' ],
83             ['Method Not Allowed'] ];
84             }
85             } else {
86 19         51 my $app = $self->routes->{$type}->{$method};
87 19 50 0     110 $app ||= $self->{app} if $self->pass_through;
88 19 100       73 if ( $app ) {
89 16 100 66     44 if (($method eq 'PATCH') && ($self->patch_types())
  2   100     41  
90 2         14 && ! grep { /^$env->{'CONTENT_TYPE'}$/msx } @{$self->patch_types()} ) {
91 1         5 [ 415, [], ['Unknown Patch Type'] ];
92             } else {
93 15         28 $app->($env);
94             }
95             } else {
96 3         21 [ 405, [ Allow => $self->{allow}->{$type} ], ['Method Not Allowed'] ];
97             }
98             }
99             }
100              
101             1;
102             __END__