File Coverage

blib/lib/Catalyst/Plugin/AtomPP.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::AtomPP;
2 1     1   21463 use strict;
  1         2  
  1         34  
3 1     1   557 use Catalyst::Action;
  0            
  0            
4             use Catalyst::Utils;
5             use XML::Atom::Entry;
6              
7             our $VERSION = '0.05_03';
8              
9             =head1 NAME
10              
11             Catalyst::Plugin::AtomPP - Dispatch AtomPP methods with Catalyst.
12              
13             =head1 SYNOPSIS
14              
15             use Catalyst qw/AtomPP/;
16              
17             sub entry : Local {
18             my ($self, $c) = @_;
19             $c->atom; # dispatch AtomPP methods.
20             }
21              
22             sub create_entry : Remote {
23             my ($self, $c, $entry) = @_;
24             # $entry is XML::Atom Object from Request content
25              
26             ...
27             }
28              
29             sub retrieve_entry : Remote {
30             my ($self, $c) = @_;
31              
32             ...
33             }
34              
35             sub update_entry : Remote {
36             ...
37             }
38              
39             sub delete_entry : Remote {
40             ...
41             }
42              
43             =head1 DESCRIPTION
44              
45             This plugin allows you to dispatch AtomPP methods with Catalyst.
46              
47             Remote method decided by HTTP Request Method. It's CRUD Model.
48              
49             ex)
50             GET /path/to/entry then retrieve_entry is called.
51             POST /path/to/entry then create_entry is called.
52              
53             If you want to decide remote method's suffix, you can set it like $c->atom('foobar').
54             Then (create|retrieve|update|delete)_foobar method is called.
55              
56             May require other authentication plugin, if needed.
57             (Authentication::CDBI::Basic, WSSE, or so)
58              
59             =head1 AUTO RESPONSE FEATURE
60              
61             If you set true value at $c->config->{atompp}->{auto_response}, AtomPP plugin set automatically $c->res->status or $c->res->body by value that Remote method returned.
62              
63             If your remote method return /^\d{3}$/ ( 200 or so ), AtomPP plugin execute $c->res->status( 200 );
64              
65             Or return XML::Atom::Entry or XML::Atom::Feed object, execute $c->res->body( $xmlatom_obj->as_xml );
66              
67             Or other not false value returned, then execute $c->res->body( $returnd_value );
68              
69             =head1 METHODS
70              
71             =over 4
72              
73             =item atom
74              
75             =cut
76              
77             sub atom {
78             my $c = shift;
79             my $method = shift;
80              
81             my $class = caller(0);
82             ($method = $c->req->action) =~ s!.*/!! unless $method;
83              
84             my %prefixes = (
85             POST => 'create_',
86             GET => 'retrieve_',
87             PUT => 'update_',
88             DELETE => 'delete_',
89             );
90              
91             if (my $prefix = $prefixes{$c->req->method}) {
92             $method = $prefix.$method;
93             } else {
94             $c->log->debug(qq!Unsupported Method "@{[$c->req->method]}" called!) if $c->debug;
95             $c->res->status(501);
96             return;
97             }
98              
99             $c->log->debug("Method: $method") if $c->debug;
100              
101             if (my $code = $class->can($method)) {
102             my $pp;
103              
104             for my $attr (@{ attributes::get($code) || [] }) {
105             $pp++ if $attr eq 'Remote';
106             }
107              
108             if ($pp) {
109             my $content = $c->req->body;
110             my $entry;
111              
112             eval{
113             $entry = XML::Atom::Entry->new( ref $content ? $content : \$content );
114             };
115              
116             $c->log->debug( $@ ) if ($c->debug and $@);
117              
118             if ($c->req->body and !$entry) {
119             $c->log->debug("Request body is not well-formed.") if $c->debug;
120             $c->res->status(415);
121             } else {
122             $class = $c->components->{$class} || $class;
123             my @args = @{$c->req->args};
124             $c->req->args([$entry]) if $entry;
125              
126             my $name = ref $class || $class;
127             my $action = Catalyst::Action->new({
128             name => $method,
129             code => $code,
130             reverse => "-> $name->$method",
131             class => $name,
132             namespace => Catalyst::Utils::class2prefix(
133             $name, $c->config->{case_sensitive}
134             ),
135             });
136             $c->state( $c->execute( $class, $action ) );
137              
138             $c->res->content_type('application/xml; charset=utf-8');
139              
140             # set status or body automaticaly
141             if ( $c->config->{atompp}->{auto_response} and $c->state ) {
142             if ( $c->state =~ /^(\d{3})$/ ) {
143             $c->log->debug("Auto Status: $1") if $c->debug;
144             $c->res->status( $1 );
145             }
146             elsif ( ref($c->state) =~ /XML::Atom::(Feed|Entry)/ ) {
147             my $xml = $c->state->as_xml;
148             if ($] >= 5.008) {
149             require Encode;
150             Encode::_utf8_off( $xml );
151             }
152             $c->res->body( $xml );
153             }
154             else {
155             $c->res->body( $c->state )
156             }
157             }
158              
159             $c->res->body($c->state);
160             $c->req->args(\@args);
161             }
162             }
163              
164             else {
165             $c->log->debug(qq!Method "$method" has no Atom attribute!) if $c->debug;
166             $c->res->status(501);
167             }
168             }
169              
170             $c->state;
171             }
172              
173             =back
174              
175             =head1 SEE ALSO
176              
177             L<Catalyst>, L<Catalyst::Plugin::XMLRPC>.
178              
179             =head1 AUTHOR
180              
181             Daisuke Murase, E<lt>typester@cpan.orgE<gt>
182              
183             =head1 COPYRIGHT
184              
185             This program is free software; you can redistribute
186             it and/or modify it under the same terms as Perl itself.
187              
188             =cut
189              
190             1;
191