File Coverage

blib/lib/Plack/Builder.pm
Criterion Covered Total %
statement 78 78 100.0
branch 19 22 86.3
condition 5 9 55.5
subroutine 22 22 100.0
pod 0 9 0.0
total 124 140 88.5


line stmt bran cond sub pod time code
1             package Plack::Builder;
2 30     30   1651898 use strict;
  30         75  
  30         1474  
3 30     30   5688 use parent qw( Exporter );
  30         6958  
  30         186  
4             our @EXPORT = qw( builder add enable enable_if mount );
5              
6 30     30   2705 use Carp ();
  30         76  
  30         745  
7 30     30   15002 use Plack::App::URLMap;
  30         106  
  30         1108  
8 30     30   18516 use Plack::Middleware::Conditional; # TODO delayed load?
  30         100  
  30         1070  
9 30     30   202 use Scalar::Util ();
  30         54  
  30         36223  
10              
11             sub new {
12 60     60 0 297402 my $class = shift;
13 60         311 bless { middlewares => [ ] }, $class;
14             }
15              
16             sub add_middleware {
17 68     68 0 277 my($self, $mw, @args) = @_;
18              
19 68 100       386 if (ref $mw ne 'CODE') {
20 67         361 my $mw_class = Plack::Util::load_class($mw, 'Plack::Middleware');
21 67     66   369 $mw = sub { $mw_class->wrap($_[0], @args) };
  66         544  
22             }
23              
24 68         123 push @{$self->{middlewares}}, $mw;
  68         529  
25             }
26              
27             sub add_middleware_if {
28 3     3 0 15 my($self, $cond, $mw, @args) = @_;
29              
30 3 100       33 if (ref $mw ne 'CODE') {
31 2         12 my $mw_class = Plack::Util::load_class($mw, 'Plack::Middleware');
32 2     2   11 $mw = sub { $mw_class->wrap($_[0], @args) };
  2         16  
33             }
34              
35 3         24 push @{$self->{middlewares}}, sub {
36 3     3   26 Plack::Middleware::Conditional->wrap($_[0], condition => $cond, builder => $mw);
37 3         6 };
38             }
39              
40             # do you want remove_middleware() etc.?
41              
42             sub _mount {
43 5     5   16 my ($self, $location, $app) = @_;
44              
45 5 50       14 if (!$self->{_urlmap}) {
46 5         63 $self->{_urlmap} = Plack::App::URLMap->new;
47             }
48              
49 5         22 $self->{_urlmap}->map($location => $app);
50 5         14 $self->{_urlmap}; # for backward compat.
51             }
52              
53             sub to_app {
54 59     59 0 171 my($self, $app) = @_;
55              
56 59 100       179 if ($app) {
    100          
57 55         201 $self->wrap($app);
58             } elsif ($self->{_urlmap}) {
59             $self->{_urlmap} = $self->{_urlmap}->to_app
60 3 50       14 if Scalar::Util::blessed($self->{_urlmap});
61 3         9 $self->wrap($self->{_urlmap});
62             } else {
63 1         228 Carp::croak("to_app() is called without mount(). No application to build.");
64             }
65             }
66              
67             sub wrap {
68 59     59 0 147 my($self, $app) = @_;
69              
70 59 100 100     238 if ($self->{_urlmap} && $app ne $self->{_urlmap}) {
71 1         122 Carp::carp("WARNING: wrap() and mount() can't be used altogether in Plack::Builder.\n" .
72             "WARNING: This causes all previous mount() mappings to be ignored.");
73             }
74              
75 59         105 for my $mw (reverse @{$self->{middlewares}}) {
  59         174  
76 70         173 $app = $mw->($app);
77             }
78              
79 59         1116 $app;
80             }
81              
82             # DSL goes here
83             our $_add = our $_add_if = our $_mount = sub {
84             Carp::croak("enable/mount should be called inside builder {} block");
85             };
86              
87 60     60 0 472 sub enable { $_add->(@_) }
88 2     2 0 35 sub enable_if(&$@) { $_add_if->(@_) }
89              
90             sub mount {
91 13     13 0 84 my $self = shift;
92 13 100       35 if (Scalar::Util::blessed($self)) {
93 5         31 $self->_mount(@_);
94             }else{
95 8         22 $_mount->($self, @_);
96             }
97             }
98              
99             sub builder(&) {
100 54     54 0 7853013 my $block = shift;
101              
102 54         582 my $self = __PACKAGE__->new;
103              
104 54         104 my $mount_is_called;
105 54         638 my $urlmap = Plack::App::URLMap->new;
106             local $_mount = sub {
107 8     8   52 $mount_is_called++;
108 8         38 $urlmap->map(@_);
109 8         29 $urlmap;
110 54         1128 };
111             local $_add = sub {
112 60     60   211 $self->add_middleware(@_);
113 54         230 };
114             local $_add_if = sub {
115 2     2   8 $self->add_middleware_if(@_);
116 54         186 };
117              
118 54         175 my $app = $block->();
119              
120 54 100       362 if ($mount_is_called) {
121 4 100       28 if ($app ne $urlmap) {
122 1         223 Carp::carp("WARNING: You used mount() in a builder block, but the last line (app) isn't using mount().\n" .
123             "WARNING: This causes all mount() mappings to be ignored.\n");
124             } else {
125 3         33 $app = $app->to_app;
126             }
127             }
128              
129 54 50 33     398 $app = $app->to_app if $app and Scalar::Util::blessed($app) and $app->can('to_app');
      33        
130              
131 54         228 $self->to_app($app);
132             }
133              
134             1;
135              
136             __END__