Added JSONP module and tests. Child of Catalyst::Action::Serialize::JSON that allows...
nebulous [Wed, 6 Jan 2010 20:29:09 +0000 (15:29 -0500)]
lib/Catalyst/Action/Serialize/JSONP.pm [new file with mode: 0644]
lib/Catalyst/Controller/REST.pm
t/jsonp.t [new file with mode: 0644]

diff --git a/lib/Catalyst/Action/Serialize/JSONP.pm b/lib/Catalyst/Action/Serialize/JSONP.pm
new file mode 100644 (file)
index 0000000..00c9f84
--- /dev/null
@@ -0,0 +1,30 @@
+package Catalyst::Action::Serialize::JSONP;
+use base 'Catalyst::Action::Serialize::JSON';
+
+sub execute {
+  my $self = shift;
+  my ($controller, $c) = @_;
+
+  my $callback_key = (
+    $controller->{'serialize'} ?
+      $controller->{'serialize'}->{'callback_key'} :
+      $controller->{'callback_key'} 
+    ) || 'callback';
+
+  if ($c->req->param($callback_key)) {
+    $self->{_jsonp_callback} = $c->req->param($callback_key);
+    $c->res->content_type('text/javascript');
+  }
+  $self->next::method($controller, $c);
+}
+
+sub serialize {
+  my $self = shift;
+  my $json = $self->next::method(@_);
+  if ($self->{_jsonp_callback}) {
+    $json = $self->{_jsonp_callback}.'('.$json.');';
+  }
+  return $json;
+}
+
+1;
index 847fa69..b7d4953 100644 (file)
@@ -146,6 +146,10 @@ Uses L<JSON> to generate JSON output.  It is strongly advised to also have
 L<JSON::XS> installed.  The C<text/x-json> content type is supported but is
 deprecated and you will receive warnings in your log.
 
+=item * C<text/javascript> => C<JSONP>
+
+If a callback=? parameter is passed, this returns javascript in the form of: $callback($serializedJSON);
+
 =item * C<text/x-data-dumper> => C<Data::Serializer>
 
 Uses the L<Data::Serializer> module to generate L<Data::Dumper> output.
@@ -268,6 +272,9 @@ __PACKAGE__->config(
         'text/x-yaml'        => 'YAML',
         'application/json'   => 'JSON',
         'text/x-json'        => 'JSON',
+        'application/x-javascript'  => 'JSONP',
+        'application/javascript'    => 'JSONP',
+        'text/javascript'    => 'JSONP',
         'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
         'text/x-data-denter' => [ 'Data::Serializer', 'Data::Denter' ],
         'text/x-data-taxi'   => [ 'Data::Serializer', 'Data::Taxi'   ],
@@ -502,6 +509,9 @@ This class provides a default configuration for Serialization.  It is currently:
          'text/x-yaml'        => 'YAML',
          'application/json'   => 'JSON',
          'text/x-json'        => 'JSON',
+         'application/x-javascript' => 'JSONP',
+         'application/javascript'   => 'JSONP',
+         'text/javascript'    => 'JSONP',
          'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
          'text/x-data-denter' => [ 'Data::Serializer', 'Data::Denter' ],
          'text/x-data-taxi'   => [ 'Data::Serializer', 'Data::Taxi'   ],
diff --git a/t/jsonp.t b/t/jsonp.t
new file mode 100644 (file)
index 0000000..70f9b18
--- /dev/null
+++ b/t/jsonp.t
@@ -0,0 +1,30 @@
+use strict;
+use warnings;
+use Test::More;
+use FindBin;
+
+use lib ("$FindBin::Bin/lib", "$FindBin::Bin/../lib");
+use Test::Rest;
+use utf8;
+
+eval 'use JSON 2.12';
+plan skip_all => 'Install JSON 2.12 or later to run this test' if ($@);
+
+plan tests => 7;
+
+use_ok 'Catalyst::Test', 'Test::Serialize', 'Catalyst::Action::Serialize::JSON';
+
+my $json = JSON->new->utf8;
+
+for ('text/javascript','application/x-javascript','application/javascript') {
+    my $t = Test::Rest->new('content_type' => $_);
+    my $monkey_template = { monkey => 'likes chicken!' };
+
+    my $mres = request($t->get(url => '/monkey_get?callback=omnivore'));
+    ok( $mres->is_success, 'GET the monkey succeeded' );
+
+    my ($json_param) = $mres->content =~ /^omnivore\((.*)?\);$/;
+    is_deeply($json->decode($json_param), $monkey_template, "GET returned the right data");
+}
+
+1;