File Coverage

blib/lib/Plack/Middleware/JSON/ForBrowsers.pm
Criterion Covered Total %
statement 68 70 97.1
branch 14 16 87.5
condition 5 6 83.3
subroutine 16 16 100.0
pod 4 4 100.0
total 107 112 95.5


line stmt bran cond sub pod time code
1             package Plack::Middleware::JSON::ForBrowsers;
2             {
3             $Plack::Middleware::JSON::ForBrowsers::VERSION = '0.002000';
4             }
5 1     1   790 use parent qw(Plack::Middleware);
  1         3  
  1         7  
6              
7             # ABSTRACT: Plack middleware which turns application/json responses into HTML
8              
9 1     1   62 use strict;
  1         3  
  1         30  
10 1     1   6 use warnings;
  1         2  
  1         34  
11 1     1   12 use Carp;
  1         2  
  1         72  
12 1     1   6 use JSON;
  1         2  
  1         7  
13 1     1   143 use MRO::Compat;
  1         3  
  1         45  
14 1     1   7 use Plack::Util::Accessor qw(json html_head html_foot);
  1         2  
  1         6  
15 1     1   3821 use List::MoreUtils qw(any);
  1         1347  
  1         97  
16 1     1   7 use Encode;
  1         2  
  1         90  
17 1     1   864 use HTML::Entities qw(encode_entities_numeric);
  1         11345  
  1         727  
18              
19              
20             chomp(my $html_head = <<'EOHTML');
21            
22            
23            
24            
25             JSON::ForBrowsers
26            
27            
39            
40            
41            
 
42             EOHTML
43              
44             (my $html_foot = <<'EOHTML') =~ s/^\s+//x;
45            
46            
47            
48             EOHTML
49              
50             my @json_types = qw(application/json);
51             my @html_types = qw(text/html application/xhtml+xml);
52              
53              
54              
55             sub new {
56 8     8 1 6788 my ($class, $arg_ref) = @_;
57              
58 8         38 my $self = $class->next::method($arg_ref);
59 8         272 $self->json(JSON->new()->utf8()->pretty());
60              
61 8 100       544 unless (defined $self->html_head()) {
62 4         48 $self->html_head($html_head);
63             }
64 8 100       53 unless (defined $self->html_foot()) {
65 4         24 $self->html_foot($html_foot);
66             }
67              
68 8         46 return $self;
69             }
70              
71              
72              
73             sub call {
74 4     4 1 42480 my($self, $env) = @_;
75              
76 4         21 my $res = $self->app->($env);
77              
78 4 100       278 unless ($self->looks_like_browser_request($env)) {
79 3         16 return $res;
80             }
81              
82             return $self->response_cb($res, sub {
83 1     1   11 my ($cb_res) = @_;
84              
85 1         5 my $h = Plack::Util::headers($cb_res->[1]);
86             # Ignore stuff like '; charset=utf-8' for now, just assume UTF-8 input
87 1 50       31 if (any { index($h->get('Content-Type'), $_) >= 0 } @json_types) {
  1         11  
88 1         47 $h->set('Content-Type' => 'text/html; charset=utf-8');
89              
90 1         41 my $json = '';
91 1         2 my $seen_last = 0;
92             return sub {
93 2 100       46 if (defined $_[0]) {
94 1         3 $json .= $_[0];
95 1         3 return '';
96             }
97             else {
98 1 50       3 if ($seen_last) {
99 0         0 return;
100             }
101             else {
102 1         2 $seen_last = 1;
103 1         4 return $self->json_to_html($json);
104             }
105             }
106 1         6 };
107             }
108 0         0 return;
109 1         12 });
110             }
111              
112              
113              
114             sub looks_like_browser_request {
115 10     10 1 24 my ($self, $env) = @_;
116              
117 10 100 66     42 if (defined $env->{HTTP_X_REQUESTED_WITH}
118             && $env->{HTTP_X_REQUESTED_WITH} eq 'XMLHttpRequest') {
119 3         13 return 0;
120             }
121              
122 7 100 100     43 if (defined $env->{HTTP_ACCEPT}
123 5     5   24 && any { index($env->{HTTP_ACCEPT}, $_) >= 0 } @html_types) {
124 3         11 return 1;
125             }
126              
127 4         15 return 0;
128             }
129              
130              
131              
132             sub json_to_html {
133 7     7 1 48 my ($self, $json) = @_;
134              
135 7         20 my $pretty_json_string = decode(
136             'UTF-8',
137             $self->json()->encode(
138             $self->json()->decode($json)
139             )
140             );
141 7         385 chomp $pretty_json_string;
142 7         20 return encode(
143             'UTF-8',
144             $self->html_head()
145             . encode_entities_numeric($pretty_json_string) .
146             $self->html_foot()
147             );
148             }
149              
150              
151             1;
152              
153              
154             __END__