File Coverage

blib/lib/Dancer/Serializer/Mutable.pm
Criterion Covered Total %
statement 67 67 100.0
branch 16 20 80.0
condition 2 3 66.6
subroutine 12 12 100.0
pod 4 5 80.0
total 101 107 94.3


line stmt bran cond sub pod time code
1             package Dancer::Serializer::Mutable;
2             our $AUTHORITY = 'cpan:SUKRIA';
3             #ABSTRACT: Serialize and deserialize content using the appropriate HTTP header
4             $Dancer::Serializer::Mutable::VERSION = '1.3514_04'; # TRIAL
5             $Dancer::Serializer::Mutable::VERSION = '1.351404';
6 4     4   1869 use strict;
  4         48  
  4         111  
7 4     4   20 use warnings;
  4         7  
  4         105  
8              
9 4     4   18 use base 'Dancer::Serializer::Abstract', 'Exporter';
  4         9  
  4         551  
10 4     4   27 use Dancer::SharedData;
  4         6  
  4         2774  
11              
12             our @EXPORT_OK = qw/ template_or_serialize /;
13              
14             my $serializer = {
15             'text/x-yaml' => 'YAML',
16             'text/html' => 'YAML',
17             'text/xml' => 'XML',
18             'text/x-json' => 'JSON',
19             'application/json' => 'JSON',
20             };
21              
22             my $loaded_serializer = {};
23             my $_content_type;
24              
25             sub template_or_serialize {
26 2     2 1 15 my( $template, $data ) = @_;
27              
28 2         4 my( $content_type ) = @{ _response_content_types(Dancer::SharedData->request) };
  2         6  
29              
30             # TODO the accept value coming from the browser can
31             # be quite complex (e.g.,
32             # text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
33             # ), but that simple heuristic should be good enough
34             # for most cases
35 2 100       16 if ( $content_type =~ qr#text/html# ) {
36 1         4 return Dancer::template(@_);
37             }
38              
39 1         5 return $data;
40             }
41              
42             sub _request_content_types {
43 17     17   48 my $request = shift;
44              
45 17         22 my $params;
46              
47 17 50       41 if ($request) {
48 17         50 $params = $request->params;
49             }
50              
51             # we push in @content_types by order of desirability
52             # I.e.: we want $content_types[0] more than $content_types[1]
53 17         27 my @content_types;
54              
55 17         41 my $method = $request->method;
56              
57 17 50       110 if ($method =~ /^(?:POST|PUT|GET|DELETE)$/) {
58             push @content_types, $request->{content_type}
59 17 100       58 if $request->{content_type};
60              
61             push @content_types, $params->{content_type}
62 17 100 66     87 if $params && $params->{content_type};
63             }
64 17         30 push @content_types, 'application/json';
65              
66             # remove duplicates
67 17         24 my %seen;
68 17         27 return [ grep { not $seen{$_}++ } @content_types ];
  26         115  
69             }
70              
71             sub _response_content_types {
72 11     11   1485 my $request = shift;
73 11         16 my @content_types;
74              
75             push @content_types, $request->{accept}
76 11 100       36 if $request->{accept};
77              
78             push @content_types, $request->{accept_type}
79 11 100       32 if $request->{'accept_type'};
80              
81             # Both above could be '*/*' which means it is our choice.
82              
83             # Default to the same format as in the request:
84 11         14 for (@{_request_content_types($request)}) {
  11         41  
85 15         30 push @content_types, $_;
86             }
87              
88             # remove duplicates
89 11         22 my %seen;
90 11         21 return [ grep { not $seen{$_}++ } @content_types ];
  20         104  
91             }
92              
93             sub serialize {
94 6     6 1 14 my ($self, $entity) = @_;
95 6         20 my $request = Dancer::SharedData->request;
96 6         19 my $content_types = _response_content_types($request);
97 6         21 my $serializer = $self->_load_serializer($request, $content_types);
98 6         33 return $serializer->serialize($entity);
99             }
100              
101             sub deserialize {
102 4     4 1 22 my ($self, $content) = @_;
103 4         16 my $request = Dancer::SharedData->request;
104 4         15 my $content_types = _request_content_types($request);
105 4         14 my $serializer = $self->_load_serializer($request, $content_types);
106 4         19 return $serializer->deserialize($content);
107             }
108              
109             sub content_type {
110 7     7 1 1593 my $self = shift;
111 7         31 $_content_type;
112             }
113              
114             sub support_content_type {
115 10     10 0 28 my ($self, $ct) = @_;
116 10         206 grep /^$ct$/, keys %$serializer;
117             }
118              
119             sub _load_serializer {
120 10     10   27 my ($self, $request, $content_types) = @_;
121              
122 10         22 foreach my $ct (@$content_types) {
123             # 'content_type' => 'text/xml; charset=utf-8'
124 10         16 my $oct = $ct;
125 10         41 $ct = (split ';', $ct)[0];
126 10 50       28 if (exists $serializer->{$ct}) {
127 10         28 my $module = "Dancer::Serializer::" . $serializer->{$ct};
128 10 100       31 if (!exists $loaded_serializer->{$module}) {
129 4 50       28 if (Dancer::ModuleLoader->load($module)) {
130 4         43 my $serializer_object = $module->new;
131 4         23 $loaded_serializer->{$module} = $serializer_object;
132             }
133             }
134 10         17 $_content_type = $oct;
135 10         39 return $loaded_serializer->{$module};
136             }
137             }
138             }
139              
140             1;
141              
142             __END__