summaryrefslogtreecommitdiff
path: root/lib/MooseX
diff options
context:
space:
mode:
authorfranck cuny <franck@lumberjaph.net>2009-12-08 10:35:46 +0100
committerfranck cuny <franck@lumberjaph.net>2009-12-08 10:35:46 +0100
commita2b7ab98ccb7083ad6bdda0839a1e2e6e21ea847 (patch)
tree309219b95ca9846f53cc078a01baa2577d3399ab /lib/MooseX
parentChecking in changes prior to tagging of version 0.01. Changelog diff is: (diff)
parentsmall updates to tests (diff)
downloadmoosex-net-api-a2b7ab98ccb7083ad6bdda0839a1e2e6e21ea847.tar.gz
Merge branch 'topic/create_tests'
* topic/create_tests: small updates to tests add a catalyst app to tests add basic tests remove meta class and method move meta class and method to new file, add meta to handle tests
Diffstat (limited to '')
-rw-r--r--lib/MooseX/Net/API.pm141
-rw-r--r--lib/MooseX/Net/API/Meta/Class.pm34
-rw-r--r--lib/MooseX/Net/API/Meta/Method.pm18
-rw-r--r--lib/MooseX/Net/API/Test.pm120
4 files changed, 250 insertions, 63 deletions
diff --git a/lib/MooseX/Net/API.pm b/lib/MooseX/Net/API.pm
index e1ab774..4e1ae5e 100644
--- a/lib/MooseX/Net/API.pm
+++ b/lib/MooseX/Net/API.pm
@@ -1,13 +1,17 @@
package MooseX::Net::API;
-use Carp;
use URI;
-use HTTP::Request;
+use Carp;
use Try::Tiny;
+use HTTP::Request;
+
+use Moose;
use Moose::Exporter;
use MooseX::Net::API::Error;
-use MooseX::Net::API::Role::Deserialize;
+use MooseX::Net::API::Meta::Class;
+use MooseX::Net::API::Meta::Method;
use MooseX::Net::API::Role::Serialize;
+use MooseX::Net::API::Role::Deserialize;
our $VERSION = '0.01';
@@ -30,6 +34,16 @@ my $reverse_content_type = {
Moose::Exporter->setup_import_methods(
with_caller => [qw/net_api_method net_api_declare/], );
+sub init_meta {
+ my ( $me, %options ) = @_;
+
+ my $for = $options{for_class};
+ Moose::Util::MetaRole::apply_metaclass_roles(
+ for_class => $for,
+ metaclass_roles => ['MooseX::Net::API::Meta::Class'],
+ );
+}
+
my ( $do_auth, $auth_method, $deserialize_method );
sub net_api_declare {
@@ -39,18 +53,13 @@ sub net_api_declare {
my $class = Moose::Meta::Class->initialize($caller);
- if ( !$options{base_url} ) {
- croak "base_url is missing in your api declaration";
- }
- else {
- $class->add_attribute(
- 'api_base_url',
- is => 'ro',
- isa => 'Str',
- lazy => 1,
- default => delete $options{base_url}
- );
- }
+ $class->add_attribute(
+ 'api_base_url',
+ is => 'rw',
+ isa => 'Str',
+ lazy => 1,
+ default => delete $options{base_url} || '',
+ );
if ( !$options{format} ) {
croak "format is missing in your api declaration";
@@ -180,37 +189,8 @@ sub net_api_method {
my $format = $self->api_format();
$url .= "." . $format if ( $self->api_format_mode() eq 'append' );
my $uri = URI->new($url);
+ my $res = _request( $self, $format, \%options, $uri, \%args );
- my $req;
- my $method = $options{method};
- if ( $method =~ /^(?:GET|DELETE)$/ || $options{params_in_url} ) {
- $uri->query_form(%args);
- $req = HTTP::Request->new( $method => $uri );
- }
- elsif ( $method =~ /^(?:POST|PUT)$/ ) {
- $req = HTTP::Request->new( $method => $uri );
- # XXX GNI
- use JSON::XS;
- $req->content( encode_json \%args );
- }
- else {
- croak "$method is not defined";
- }
-
- # XXX check presence content type
- $req->header( 'Content-Type' => $list_content_type->{$format} )
- if $self->api_format_mode eq 'content-type';
-
- if ($do_auth) {
- if ($auth_method) {
- $req = $self->$auth_method($req);
- }
- else {
- $req = _do_authentication( $self, $req );
- }
- }
-
- my $res = $self->useragent->request($req);
my $content_type = $res->headers->{"content-type"};
$content_type =~ s/(;.+)$//;
@@ -249,6 +229,7 @@ sub net_api_method {
%options,
),
);
+ $class->_add_api_method($name);
}
sub _add_useragent {
@@ -277,6 +258,41 @@ sub _add_useragent {
);
}
+sub _request {
+ my ( $self, $format, $options, $uri, $args ) = @_;
+
+ my $req;
+ my $method = $options->{method};
+ if ( $method =~ /^(?:GET|DELETE)$/ || $options->{params_in_url} ) {
+ $uri->query_form(%$args);
+ $req = HTTP::Request->new( $method => $uri );
+ }
+ elsif ( $method =~ /^(?:POST|PUT)$/ ) {
+ $req = HTTP::Request->new( $method => $uri );
+
+ # XXX proper serialisation
+ use JSON::XS;
+ $req->content( encode_json $args );
+ }
+ else {
+ croak "$method is not defined";
+ }
+
+ $req->header( 'Content-Type' => $list_content_type->{$format} )
+ if $self->api_format_mode eq 'content-type';
+
+ if ($do_auth) {
+ if ($auth_method) {
+ $req = $self->$auth_method($req);
+ }
+ else {
+ $req = _do_authentication( $self, $req );
+ }
+ }
+
+ return $self->useragent->request($req);
+}
+
sub _do_authentication {
my ( $caller, $req ) = @_;
$req->headers->authorization_basic( $caller->api_username,
@@ -305,23 +321,6 @@ sub _do_deserialization {
}
}
-package MooseX::Net::API::Meta::Method;
-
-use Moose;
-extends 'Moose::Meta::Method';
-
-has description => ( is => 'ro', isa => 'Str' );
-has path => ( is => 'ro', isa => 'Str', required => 1 );
-has method => ( is => 'ro', isa => 'Str', required => 1 );
-has params => ( is => 'ro', isa => 'ArrayRef', required => 0 );
-has required => ( is => 'ro', isa => 'ArrayRef', required => 0 );
-
-sub new {
- my $class = shift;
- my %args = @_;
- $class->SUPER::wrap(@_);
-}
-
1;
__END__
@@ -338,6 +337,7 @@ MooseX::Net::API - Easily create client for net API
# we declare an API, the base_url is http://exemple.com/api
# the format is json and it will be happened to the query
+ # You can set base_url later, calling $my_obj->api_base_url('http://..')
net_api_declare my_api => (
base_url => 'http://exemple.com/api',
format => 'json',
@@ -426,6 +426,23 @@ HTTP method (GET, POST, PUT, DELETE)
path of the query.
+If you defined your path and params like this
+
+ net_api_method user_comments => (
+ ...
+ path => '/user/$user/list/$date/',
+ params => [qw/user date foo bar/],
+ ...
+ );
+
+and you call
+
+ $obj->user_comments(user => 'franck', date => 'today', foo => 1, bar => 2);
+
+the url generetad will look like
+
+ /user/franck/list/today/?foo=1&bar=2
+
=item B<params> [arrayref]
list of params.
diff --git a/lib/MooseX/Net/API/Meta/Class.pm b/lib/MooseX/Net/API/Meta/Class.pm
new file mode 100644
index 0000000..80075f8
--- /dev/null
+++ b/lib/MooseX/Net/API/Meta/Class.pm
@@ -0,0 +1,34 @@
+package MooseX::Net::API::Meta::Class;
+
+use Moose::Role;
+use Moose::Meta::Class;
+use MooseX::Types::Moose qw(Str ArrayRef ClassName Object);
+
+has local_api_methods => (
+ traits => ['Array'],
+ is => 'ro',
+ isa => ArrayRef [Str],
+ required => 1,
+ default => sub { [] },
+ auto_deref => 1,
+ handles => { '_add_api_method' => 'push' },
+);
+has local_api_test_methods => (
+ traits => ['Array'],
+ is => 'ro',
+ isa => ArrayRef [Str],
+ required => 1,
+ default => sub { [] },
+ auto_deref => 1,
+ handles => { '_add_api_test_method' => 'push' },
+);
+
+sub _build_meta_class {
+ my $self = shift;
+ return Moose::Meta::Class->create_anon_class(
+ superclasses => [ $self->method_metaclass ],
+ cache => 1,
+ );
+}
+
+1;
diff --git a/lib/MooseX/Net/API/Meta/Method.pm b/lib/MooseX/Net/API/Meta/Method.pm
new file mode 100644
index 0000000..74f9a07
--- /dev/null
+++ b/lib/MooseX/Net/API/Meta/Method.pm
@@ -0,0 +1,18 @@
+package MooseX::Net::API::Meta::Method;
+
+use Moose;
+extends 'Moose::Meta::Method';
+
+has description => ( is => 'ro', isa => 'Str' );
+has path => ( is => 'ro', isa => 'Str', required => 1 );
+has method => ( is => 'ro', isa => 'Str', required => 1 );
+has params => ( is => 'ro', isa => 'ArrayRef', required => 0 );
+has required => ( is => 'ro', isa => 'ArrayRef', required => 0 );
+
+sub new {
+ my $class = shift;
+ my %args = @_;
+ $class->SUPER::wrap(@_);
+}
+
+1;
diff --git a/lib/MooseX/Net/API/Test.pm b/lib/MooseX/Net/API/Test.pm
index 2f2e428..e991b7f 100644
--- a/lib/MooseX/Net/API/Test.pm
+++ b/lib/MooseX/Net/API/Test.pm
@@ -1,13 +1,131 @@
package MooseX::Net::API::Test;
+use lib ('t/lib');
+use Try::Tiny;
+
+use Test::More;
+use Moose;
use Moose::Exporter;
+use MooseX::Net::API::Meta::Class;
+use MooseX::Net::API::Meta::Method;
+
+Moose::Exporter->setup_import_methods(
+ with_caller => [qw/test_api_method test_api_declare run/] );
+
+my $api_to_test;
+
+sub init_meta {
+ my ( $me, %options ) = @_;
+
+ my $for = $options{for_class};
+ Moose::Util::MetaRole::apply_metaclass_roles(
+ for_class => $for,
+ metaclass_roles => ['MooseX::Net::API::Meta::Class'],
+ );
+}
+
+my $list_content_type = {
+ 'json' => 'application/json',
+ 'yaml' => 'text/x-yaml',
+ 'xml' => 'text/xml',
+};
+
+my $tests_count = 0;
+
+sub test_api_declare {
+ my $caller = shift;
+ my $name = shift;
+ my %options = @_;
+
+ unless ( Class::MOP::is_class_loaded($name) ) {
+ Class::MOP::load_class($name);
+ }
-Moose::Exporter->setup_import_methods( with_caller => [qw/test_api_method/] );
+ $api_to_test = $name;
+
+ if ( $options{catalyst} ) {
+ my $app = $options{catalyst_app_name};
+
+ Class::MOP::load_class("HTTP::Request");
+ Class::MOP::load_class("Catalyst::Test");
+
+ Catalyst::Test->import($app);
+
+ my $res = __PACKAGE__->meta->remove_method('_request');
+ MooseX::Net::API->meta->add_method(
+ '_request' => sub {
+ my ( $class, $format, $options, $uri, $args ) = @_;
+ my $method = $options->{method};
+
+ my $res;
+ if ( $method =~ /^(?:GET|DELETE)$/
+ || $options->{params_in_url} )
+ {
+ $uri->query_form(%$args);
+ my $req = HTTP::Request->new( $method => $uri );
+ $req->header(
+ 'Content-Type' => $list_content_type->{$format} );
+ $res = request($req);
+ }
+ else {
+ my $req = HTTP::Request->new( $method => $uri );
+ $req->header(
+ 'Content-Type' => $list_content_type->{$format} );
+ $req->header( 'Content' => Dump $args);
+ $res = request($req);
+ }
+ return $res;
+ }
+ );
+ }
+}
sub test_api_method {
my $caller = shift;
my $name = shift;
my %options = @_;
+
+ my $meta = $api_to_test->meta;
+ my $method = $meta->find_method_by_name($name);
+
+ if ( !$method ) {
+ die "method $name does not exists\n";
+ }
+
+ my $class = Moose::Meta::Class->initialize($caller);
+ foreach my $test_name ( keys %{ $options{tests} } ) {
+ foreach my $test ( @{ $options{tests}{$test_name} } ) {
+ __PACKAGE__->meta->add_method(
+ $test_name => sub {
+ my $res = $method->execute( $api_to_test->new );
+ if (ref $test eq 'HASH') {
+ my $action = $test->{test};
+ my $result = $test->{expected};
+ # XXX sucky sucky sucky
+ if ( $action eq 'is_deeply' ) {
+ is_deeply( $res, $result );
+ }
+ }else{
+ if ($test eq 'ok') {
+ ok $res;
+ }
+ }
+ }
+ );
+ $class->_add_api_test_method($test_name);
+ }
+ }
+}
+
+sub run {
+ my $caller = shift;
+
+ my $class = Moose::Meta::Class->initialize($caller);
+ my @test_methods = $class->local_api_test_methods();
+ foreach my $m (@test_methods) {
+ my $method = __PACKAGE__->meta->find_method_by_name($m);
+ $method->execute();
+ }
}
1;