File Coverage

blib/lib/Net/Twitter/API.pm
Criterion Covered Total %
statement 78 79 98.7
branch 27 32 84.3
condition 5 9 55.5
subroutine 127 128 99.2
pod 4 5 80.0
total 241 253 95.2


line stmt bran cond sub pod time code
1             package Net::Twitter::API;
2             $Net::Twitter::API::VERSION = '4.01010';
3 30     61   119 use Moose ();
  30         43  
  30         621  
4 30     30   98 use Carp::Clan qw/^(?:Net::Twitter|Moose|Class::MOP)/;
  30         36  
  30         143  
5 30     30   3769 use Moose::Exporter;
  30         40  
  30         173  
6 30     30   1075 use URI::Escape;
  30         78  
  30         1512  
7 30     30   15721 use DateTime::Format::Strptime;
  30         156399  
  30         1741  
8              
9 30     30   278 use namespace::autoclean;
  30         34  
  30         259  
10              
11             Moose::Exporter->setup_import_methods(
12             with_caller => [ qw/base_url authenticate datetime_parser twitter_api_method/ ],
13             );
14              
15             my $_base_url;
16 87     87 1 422 sub base_url { $_base_url = $_[1] }
17              
18             # kludge: This is very transient!
19             my $do_auth;
20 87     87 1 289 sub authenticate { $do_auth = $_[1] }
21              
22             # provide a default: we'll use the format of the REST API
23             my $datetime_parser = DateTime::Format::Strptime->new(pattern => '%a %b %d %T %z %Y');
24 72     72 1 387 sub datetime_parser { $datetime_parser = $_[1] }
25              
26             sub twitter_api_method {
27 3413     3413 1 8938 my $caller = shift;
28 3413         3406 my $name = shift;
29 3413         18664 my %options = (
30             authenticate => $do_auth,
31             datetime_parser => $datetime_parser,
32             base_url_method => $_base_url,
33             path_suffix => '.json',
34             @_,
35             );
36              
37 0     0   0 my $deprecation_coderef = ref $options{deprecated} eq ref sub {}
38 1     1   6 ? sub { $options{deprecated}->($name) }
39 3413 100   666   18900 : sub {};
  666         594  
40              
41 3413         13696 my $class = Moose::Meta::Class->initialize($caller);
42              
43 3413         37721 my ($arg_names, $path) = @options{qw/required path/};
44 3413 100 100     7411 $arg_names = $options{params} if @$arg_names == 0 && @{$options{params}} == 1;
  1894         5689  
45              
46             my $code = sub {
47 667     667   348600 my $self = shift;
        667      
        667      
        698      
        698      
        492      
        667      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        382      
        667      
        698      
        698      
        698      
        698      
        698      
        935      
        698      
        698      
        698      
        492      
        667      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        698      
        492      
        461      
        718      
        749      
        986      
        749      
        986      
        986      
        749      
        749      
        749      
        986      
        986      
        780      
        955      
        749      
        986      
        749      
        749      
        698      
        698      
        698      
        698      
        698      
        935      
        698      
        698      
        698      
        631      
        667      
        698      
        698      
        935      
        935      
        698      
        698      
        698      
        492      
        667      
        698      
        492      
        667      
        935      
        698      
        729      
        667      
        698      
        698      
        935      
        698      
        698      
        698      
        698      
        698      
        935      
        698      
        382      
        667      
        935      
        935      
        698      
        698      
        237      
48              
49             # give the deprecation coderef early access in case it intends to die
50 667         1358 $deprecation_coderef->();
51              
52             # copy callers args since we may add ->{source}
53 667 100       2165 my $args = ref $_[-1] eq 'HASH' ? { %{pop @_} } : {};
  218         602  
54              
55             # flatten array arguments
56 667         1103 for ( qw/id user_id screen_name/ ) {
57 2001 100       3681 $args->{$_} = join ',' => @{ $args->{$_} } if ref $args->{$_} eq 'ARRAY';
  9         36  
58             }
59              
60 667         2214 $self->_remap_legacy_synthetic_args($args);
61              
62 667 100       1541 croak sprintf "$name expected %d args", scalar @$arg_names if @_ > @$arg_names;
63              
64             # promote positional args to named args
65 666         1498 for ( my $i = 0; @_; ++$i ) {
66 239         335 my $param = $arg_names->[$i];
67 239 50       446 croak "duplicate param $param: both positional and named"
68             if exists $args->{$param};
69              
70 239         615 $args->{$param} = shift;
71             }
72              
73 666 100 33     1703 $args->{source} ||= $self->source if $options{add_source};
74              
75 666 100       1880 my $authenticate = exists $args->{-authenticate} ? $args->{-authenticate} : $options{authenticate};
76              
77             # promote boolean parameters
78 666         597 for my $boolean_arg ( @{ $options{booleans} } ) {
  666         1357  
79 617 100       1359 if ( exists $args->{$boolean_arg} ) {
80 8 50       23 next if $args->{$boolean_arg} =~ /^true|false$/;
81 8 100       23 $args->{$boolean_arg} = $args->{$boolean_arg} ? 'true' : 'false';
82             }
83             }
84              
85             # Workaround Twitter bug: any value passed for skip_user is treated as true.
86             # The only way to get 'false' is to not pass the skip_user at all.
87 666 50 33     1571 delete $args->{skip_user} if exists $args->{skip_user} && $args->{skip_user} eq 'false';
88              
89             # replace placeholder arguments
90 666         790 my $local_path = $path;
91 666 100       1607 $local_path =~ s,/:id$,, unless exists $args->{id}; # remove optional trailing id
92 666 50       1358 $local_path =~ s/:(\w+)/delete $args->{$1} or croak "required arg '$1' missing"/eg;
  179         696  
93              
94 666         675 my $uri = URI->new($self->${ \$options{base_url_method} } . "/$local_path$options{path_suffix}");
  666         22459  
95              
96 666         154925 return $self->_json_request(
97             $options{method},
98             $uri,
99             $args,
100             $authenticate,
101             $options{datetime_parser},
102             );
103 3413         12743 };
104              
105 3413         14209 $class->add_method(
106             $name,
107             Net::Twitter::Meta::Method->new(
108             name => $name,
109             package_name => $caller,
110             body => $code,
111             %options,
112             ),
113             );
114              
115 3413 100       6054065 $class->add_method($_, $code) for @{$options{aliases} || []};
  3413         22019  
116             }
117              
118             package Net::Twitter::Meta::Method;
119             $Net::Twitter::Meta::Method::VERSION = '4.01010';
120 30     30   18930 use Moose;
  30         46  
  30         174  
121 30     30   138803 use Carp::Clan qw/^(?:Net::Twitter|Moose|Class::MOP)/;
  30         79  
  30         203  
122             extends 'Moose::Meta::Method';
123              
124 30     30   4911 use namespace::autoclean;
  30         47  
  30         140  
125              
126             has description => ( isa => 'Str', is => 'ro', required => 1 );
127             has aliases => ( isa => 'ArrayRef[Str]', is => 'ro', default => sub { [] } );
128             has path => ( isa => 'Str', is => 'ro', required => 1 );
129             has method => ( isa => 'Str', is => 'ro', default => 'GET' );
130             has add_source => ( isa => 'Bool', is => 'ro', default => 0 );
131             has params => ( isa => 'ArrayRef[Str]', is => 'ro', default => sub { [] } );
132             has required => ( isa => 'ArrayRef[Str]', is => 'ro', default => sub { [] } );
133             has returns => ( isa => 'Str', is => 'ro', predicate => 'has_returns' );
134             has deprecated => ( isa => 'Bool|CodeRef', is => 'ro', default => 0 );
135             has booleans => ( isa => 'ArrayRef[Str]', is => 'ro', default => sub { [] } );
136             has authenticate => ( isa => 'Bool', is => 'ro', required => 1 );
137             has datetime_parser => ( is => 'ro', required => 1 );
138             has base_url_method => ( isa => 'Str', is => 'ro', required => 1 );
139             has path_suffix => ( isa => 'Str', is => 'ro', required => 1 );
140              
141             # TODO: can MooseX::StrictConstructor be made to work here?
142             my %valid_attribute_names = map { $_->init_arg => 1 }
143             __PACKAGE__->meta->get_all_attributes;
144              
145             sub new {
146 3413     3444 0 3253 my $class = shift;
147 3413         11225 my %args = @_;
148              
149 3413         7396 my @invalid_attributes = grep { !$valid_attribute_names{$_} } keys %args;
  46827         44098  
150 3413 50       6753 croak "unexpected argument(s): @invalid_attributes" if @invalid_attributes;
151              
152 3413         10286 $class->SUPER::wrap(@_);
153             }
154              
155             1;
156              
157             __END__
158              
159             =head1 NAME
160              
161             Net::Twitter::API - Moose sugar for defining Twitter API methods
162              
163             =head1 VERSION
164              
165             version 4.01010
166              
167             =head1 SYNOPSIS
168              
169             package My::Twitter::API;
170             use Moose::Role;
171             use Net::Twitter::API;
172              
173             use namespace::autoclean;
174              
175             has apiurl => ( isa => 'Str', is => 'rw', default => 'http://twitter.com' );
176              
177             base_url 'apiurl';
178              
179             twitter_api_method friends_timeline => (
180             description => <<'',
181             Returns the 20 most recent statuses posted by the authenticating user
182             and that user's friends. This is the equivalent of /home on the Web.
183              
184             aliases => [qw/following_timeline/],
185             path => 'statuses/friends_timeline',
186             method => 'GET',
187             params => [qw/since_id max_id count page/],
188             required => [],
189             returns => 'ArrayRef[Status]',
190             );
191              
192             1;
193              
194             =head1 DESCRIPTION
195              
196             This module provides some Moose sugar for defining Twitter API methods. It is part
197             of the Net-Twitter distribution on CPAN and is used by C<Net::Twitter::API::RESTv1_1>,
198             C<Net::Twitter::API::Search>, and perhaps others.
199              
200             It's intent is to make maintaining C<Net::Twitter> as easy as possible.
201              
202             =head1 METHODS
203              
204             =over 4
205              
206             =item base_url
207              
208             Specifies, by name, the attribute which contains the base URL for the defined API.
209              
210             =item twitter_api_method
211              
212             Defines a Twitter API method. Valid arguments are:
213              
214             =over 4
215              
216             =item authenticate
217              
218             Specifies whether, by default, API methods calls should authenticate.
219              
220             =item datetime_parser
221              
222             Specifies the Date::Time::Format derived parser to use for parsing and
223             formatting date strings for the API being defined.
224              
225             =item description
226              
227             A string describing the method, suitable for documentation.
228              
229             =item aliases
230              
231             An ARRAY ref of strings containing alternate names for the method.
232              
233             =item path
234              
235             A string containing the path part of the API URL
236              
237             =item path_suffix
238              
239             A string containing an additional suffix to append to the path (for
240             legacy reasons). If you want to suffix appended, pass the empty
241             string. Defaults to ".json".
242              
243             =item method
244              
245             A string containing the HTTP method for the call. Defaults to "GET".
246              
247             =item add_source
248              
249             A boolean, indicating whether or not the C<source> parameter should be added
250             to the API call. (The source value is assigned by Twitter for registered
251             applications.) Defaults to 0.
252              
253             =item params
254              
255             An ARRAY ref of strings naming all of the valid parameters. Defaults to an
256             empty ARRAY ref.
257              
258             =item required
259              
260             An ARRAY ref of strings naming all of the required parameters. Defaults to an
261             empty ARRAY ref.
262              
263             =item returns
264              
265             A string describing the return type of the API method call.
266              
267             =item deprecated
268              
269             A boolean indicating whether or not this API is deprecated. If set to 1, code
270             for the method will be created. This option is optional, and is used by the
271             C<Net-Twitter> distribution when generating documentation. It defaults to 0.
272              
273             =back
274              
275             =back
276              
277             =head1 AUTHOR
278              
279             Marc Mims <marc@questright.com>
280              
281             =head1 LICENSE
282              
283             Copyright (c) 2009 Marc Mims
284              
285             The Twitter API itself, and the description text used in this module is:
286              
287             Copyright (c) 2009 Twitter
288              
289             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
290              
291             =head1 DISCLAIMER OF WARRANTY
292              
293             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
294             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
295             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
296             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
297             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
298             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
299             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
300             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
301             NECESSARY SERVICING, REPAIR, OR CORRECTION.
302              
303             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
304             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
305             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE
306             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
307             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
308             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
309             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
310             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
311             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
312             SUCH DAMAGES.