File Coverage

blib/lib/Dancer2/Serializer/Mutable.pm
Criterion Covered Total %
statement 24 24 100.0
branch 5 6 83.3
condition n/a
subroutine 6 6 100.0
pod n/a
total 35 36 97.2


line stmt bran cond sub pod time code
1             package Dancer2::Serializer::Mutable;
2             # ABSTRACT: Serialize and deserialize content based on HTTP header
3             $Dancer2::Serializer::Mutable::VERSION = '2.0.1';
4 3     3   615922 use Moo;
  3         31676  
  3         20  
5 3     3   6947 use Carp 'croak';
  3         6  
  3         185  
6 3     3   1301 use Encode;
  3         44939  
  3         389  
7 3     3   1806 use Module::Runtime 'require_module';
  3         7065  
  3         25  
8             with 'Dancer2::Core::Role::Serializer';
9              
10 3     3   276 use constant DEFAULT_CONTENT_TYPE => 'application/json';
  3         6  
  3         2614  
11              
12             has '+content_type' => ( default => DEFAULT_CONTENT_TYPE() );
13              
14             my $serializer = {
15             'YAML' => {
16             to => sub { Dancer2::Core::DSL::to_yaml(@_) },
17             from => sub { Dancer2::Core::DSL::from_yaml(@_) },
18             },
19             'Dumper' => {
20             to => sub { Dancer2::Core::DSL::to_dumper(@_) },
21             from => sub { Dancer2::Core::DSL::from_dumper(@_) },
22             },
23             'JSON' => {
24             to => sub { Dancer2::Core::DSL::to_json(@_) },
25             from => sub { Dancer2::Core::DSL::from_json(@_) },
26             },
27             };
28              
29             has mapping => (
30             is => 'ro',
31             lazy => 1,
32             default => sub {
33             my $self = shift;
34              
35             if ( my $mapping = $self->config->{mapping} ) {
36              
37             # initialize non-default serializers
38             for my $s ( values %$mapping ) {
39             # TODO allow for arguments via the config
40             next if $serializer->{$s};
41             my $serializer_class = "Dancer2::Serializer::$s";
42             require_module($serializer_class);
43             my $serializer_object = $serializer_class->new;
44             $serializer->{$s} = {
45             from => sub { shift; $serializer_object->deserialize(@_) },
46             to => sub { shift; $serializer_object->serialize(@_) },
47             };
48             }
49              
50             return $mapping;
51             }
52              
53              
54             return {
55             'text/x-yaml' => 'YAML',
56             'text/html' => 'YAML',
57             'text/x-data-dumper' => 'Dumper',
58             'text/x-json' => 'JSON',
59             'application/json' => 'JSON',
60             }
61             },
62             );
63              
64             sub serialize {
65             my ( $self, $entity ) = @_;
66              
67             # Look for valid format in the headers
68             my $format = $self->_get_content_type('accept');
69              
70             # Match format with a serializer and return
71             $format and return $serializer->{$format}{'to'}->(
72             $self, $entity
73             );
74              
75             # If none is found then just return the entity without change
76             return $entity;
77             }
78              
79             sub deserialize {
80             my ( $self, $content ) = @_;
81              
82             my $format = $self->_get_content_type('content_type');
83             $format and return $serializer->{$format}{'from'}->($self, $content);
84              
85             return $content;
86             }
87              
88             sub _get_content_type {
89 51     51   118 my ($self, $header) = @_;
90              
91 51 50       172 if ( $self->has_request ) {
92             # Search for the first HTTP header variable which specifies
93             # supported content. Both content_type and accept are checked
94             # for backwards compatibility.
95 51         162 foreach my $method ( $header, qw ) {
96 91 100       4776 if ( my $value = $self->request->header($method) ) {
97 50 100       7096 if ( my $serializer = $self->mapping->{$value} ) {
98 41         1199 $self->set_content_type($value);
99 41         1393 return $serializer;
100             }
101             }
102             }
103             }
104              
105             # If none if found, return the default, 'JSON'.
106 10         432 $self->set_content_type( DEFAULT_CONTENT_TYPE() );
107 10         309 return 'JSON';
108             }
109              
110             1;
111              
112             __END__