Codebase list libnet-twitter-perl / 2ac4b30
[svn-upgrade] new version libnet-twitter-perl (3.17001) Alessandro Ghedini 13 years ago
28 changed file(s) with 709 addition(s) and 331 deletion(s). Raw diff Collapse all Expand all
0 3.17001 2011-03-31
1 - fixed intermittent bug in AutoCursor (result of Class::MOP anon class caching)
2
3 3.17000 2011-03-29
4 - production release with new AutoCursor trait
5
6 3.16000_1 2011-03-27
7 - Added AutoCursor trait
8
9 3.16000 2011-03-26
10 - Moved trends methods to API::REST; added warning to API::Search::Trends
11 - Added no_retweet_ids method
12 - modify searchapiurl for identica option
13 - added deprecation notice to Net::Identica with Net::Twitter examples
14 - replaced Test::Exception with Test::Fatal in tests
15
016 3.15000 2011-02-25
117 - added Lists API method members_create_all (alias add_list_members)
218 - added tests dependency: Test::Exception (closes RT #65786)
2525 lib/Net/Twitter/Role/API/Search.pm
2626 lib/Net/Twitter/Role/API/Search/Trends.pm
2727 lib/Net/Twitter/Role/API/TwitterVision.pm
28 lib/Net/Twitter/Role/AutoCursor.pm
2829 lib/Net/Twitter/Role/InflateObjects.pm
2930 lib/Net/Twitter/Role/Legacy.pm
3031 lib/Net/Twitter/Role/OAuth.pm
6162 t/99-pod_coverage.t
6263 t/99-pod_spelling.t
6364 t/99-pod_syntax.t
65 t/auto-cursor.t
6466 t/geo.t
6567 t/leak.t
6668 t/lib/TestUA.pm
33 - 'Marc Mims <marc@questright.com> (@semifor on Twitter)'
44 build_requires:
55 ExtUtils::MakeMaker: 6.42
6 Test::Exception: 0
6 Test::Fatal: 0
77 Test::More: 0.88
88 configure_requires:
99 ExtUtils::MakeMaker: 6.42
2929 Devel::StackTrace: 1.21
3030 Digest::HMAC_SHA1: 0
3131 Digest::SHA: 0
32 Digest::SHA1: 0
3233 Encode: 0
3334 File::Spec: 0
3435 HTML::Entities: 0
4142 Moose::Exporter: 0
4243 Moose::Role: 0
4344 MooseX::MultiInitArg: 0
45 MooseX::Role::Parameterized: 0
4446 Net::Netrc: 0
4547 Net::OAuth: 0.25
4648 Scalar::Util: 0
5557 homepage: http://github.com/semifor/Net-Twitter
5658 license: http://dev.perl.org/licenses/
5759 repository: git://github.com/semifor/Net-Twitter.git
58 version: 3.15000
60 version: 3.17001
33 perl_version_from 'lib/Net/Twitter/Core.pm';
44
55 if ( $Module::Install::AUTHOR ) {
6 $ENV{NET_TWITTER_NO_TRENDS_WARNING} = 1;
67 system $^X, "src/build.pl", version, 'src/net-twitter-pod.tt2', 'lib/Net/Twitter.pod';
78 system 'pod2text lib/Net/Twitter.pod > README';
89 }
2627 requires 'DateTime::Format::Strptime'=> 1.09;
2728 requires 'Devel::StackTrace' => 1.21;
2829 requires 'Digest::HMAC_SHA1';
30 requires 'Digest::SHA1';
2931 requires 'Encode';
3032 requires 'HTML::Entities';
3133 requires 'HTTP::Request::Common';
3537 requires 'Moose::Exporter';
3638 requires 'Moose::Role';
3739 requires 'MooseX::MultiInitArg';
40 requires 'MooseX::Role::Parameterized';
3841 requires 'namespace::autoclean' => 0.09;
3942 requires 'Net::OAuth' => 0.25;
4043 requires 'Scalar::Util';
4346 requires 'URI::Escape';
4447 requires 'Try::Tiny' => 0.03;
4548
46 test_requires 'Test::Exception';
49 test_requires 'Test::Fatal';
4750 test_requires 'Test::More' => 0.88; # for done_testing
4851
4952 # Don't rely on the JSON::Any requirement to pull in a suitable JSON backend.
11 Net::Twitter - A perl interface to the Twitter API
22
33 VERSION
4 This document describes Net::Twitter version 3.15000
4 This document describes Net::Twitter version 3.17001
55
66 SYNOPSIS
77 use Net::Twitter;
104104 Provides support for the TwitterVision API. See
105105 <http://twittervision.com/api.html>.
106106
107 WrapError
108 "Net::Twitter" normally throws exceptions on error. When
109 this trait is included, "Net::Twitter" returns undef when a
110 method fails and makes the error available through method
111 "get_error". This is the way all errors were handled in
112 Net::Twitter versions prior to version 3.00.
113
114 OAuth
115 The "OAuth" trait provides OAuth authentication rather than
116 the default Basic Authentication for Twitter API method
117 calls. See the "Authentication" section and
118 Net::Twitter::Role::OAuth for full documentation.
107 AutoCursor
108 "AutoCursor" is a parameterized trait that provides an
109 automatic loop for cursored calls, returning an ARRAY
110 reference to the combined results. By default, it handles
111 "friends_ids" and "followers_ids". See
112 Net::Twitter::Role::AutoCursor for details.
119113
120114 InflateObjects
121115 When this optional trait is included, Net::Twitter inflates
144138 # etc.
145139 print $r->relative_created_at;
146140
147 RateLimit
148 The "RateLimit" trait adds utility methods that return
149 information about the current rate limit status. See
150 Net::Twitter::Role::RateLimit for details.
151
152141 Legacy
153142 This trait provides backwards compatibility to
154143 "Net::Twitter" versions prior to 3.00. It implies the traits
162151 backwards compatibility for existing applications using
163152 "Net::Twitter" versions prior to 3.00. See section "LEGACY
164153 COMPATIBILITY" for more details.
154
155 OAuth
156 The "OAuth" trait provides OAuth authentication rather than
157 the default Basic Authentication for Twitter API method
158 calls. See the "Authentication" section and
159 Net::Twitter::Role::OAuth for full documentation.
160
161 RateLimit
162 The "RateLimit" trait adds utility methods that return
163 information about the current rate limit status. See
164 Net::Twitter::Role::RateLimit for details.
165
166 RetryOnError
167 The "RetryOnError" trait automatically retries Twitter API
168 calls with temporary failures. See
169 Net::Twitter::Role::RetryOnError for details.
170
171 WrapError
172 "Net::Twitter" normally throws exceptions on error. When
173 this trait is included, "Net::Twitter" returns undef when a
174 method fails and makes the error available through method
175 "get_error". This is the way all errors were handled in
176 Net::Twitter versions prior to version 3.00.
165177
166178 Some examples of using the "traits" parameter in "new":
167179
968980
969981 Returns: DirectMessage
970982
983 no_retweet_ids
984
985 Parameters: *none*
986 Required: *none*
987
988 Returns an ARRAY ref of user IDs for which the authenticating user
989 does not want to receive retweets.
990
991 Returns: ArrayRef[UserIDs]
992
971993 public_timeline
972994
973995 Parameters: skip_user, trim_user, include_entities
12781300
12791301 Returns: Str
12801302
1303 trends
1304
1305 Parameters: *none*
1306 Required: *none*
1307
1308 Returns the top ten queries that are currently trending on Twitter.
1309 The response includes the time of the request, the name of each
1310 trending topic, and the url to the Twitter Search results page for
1311 that topic.
1312
1313 Returns: ArrayRef[Query]
1314
12811315 trends_available
12821316
12831317 Parameters: lat, long
12981332 specific location.
12991333
13001334 Returns: ArrayRef[Location]
1335
1336 trends_current
1337 trends_current(exclude)
1338
1339 Parameters: exclude
1340 Required: *none*
1341
1342 Returns the current top ten trending topics on Twitter. The response
1343 includes the time of the request, the name of each trending topic,
1344 and query used on Twitter Search results page for that topic.
1345
1346 Returns: HashRef
1347
1348 trends_daily
1349
1350 Parameters: date, exclude
1351 Required: *none*
1352
1353 Returns the top 20 trending topics for each hour in a given day.
1354
1355 Returns: HashRef
13011356
13021357 trends_location
13031358 trends_location(woeid)
13161371
13171372 Returns: ArrayRef[Trend]
13181373
1374 trends_weekly
1375
1376 Parameters: date, exclude
1377 Required: *none*
1378
1379 Returns the top 30 trending topics for each day in a given week.
1380
1381 Returns: HashRef
1382
13191383 update
13201384 update(status)
13211385
15201584 search
15211585 search(q)
15221586
1523 Parameters: q, callback, lang, rpp, page, since_id, geocode,
1524 show_user
1587 Parameters: q, callback, lang, locale, rpp, page, since_id, until,
1588 geocode, show_user, result_type
15251589 Required: q
15261590
15271591 Returns a HASH reference with some meta-data about the query
15331597 for my $status ( @{$r->{results}} ) {
15341598 print "$status->{text}\n";
15351599 }
1536
1537 Returns: HashRef
1538
1539 trends
1540
1541 Parameters: *none*
1542 Required: *none*
1543
1544 Returns the top ten queries that are currently trending on Twitter.
1545 The response includes the time of the request, the name of each
1546 trending topic, and the url to the Twitter Search results page for
1547 that topic.
1548
1549 Returns: ArrayRef[Query]
1550
1551 trends_current
1552 trends_current(exclude)
1553
1554 Parameters: exclude
1555 Required: *none*
1556
1557 Returns the current top ten trending topics on Twitter. The response
1558 includes the time of the request, the name of each trending topic,
1559 and query used on Twitter Search results page for that topic.
1560
1561 Returns: HashRef
1562
1563 trends_daily
1564
1565 Parameters: date, exclude
1566 Required: *none*
1567
1568 Returns the top 20 trending topics for each hour in a given day.
1569
1570 Returns: HashRef
1571
1572 trends_weekly
1573
1574 Parameters: date, exclude
1575 Required: *none*
1576
1577 Returns the top 30 trending topics for each day in a given week.
15781600
15791601 Returns: HashRef
15801602
11 use Moose;
22
33 # use *all* digits for fBSD ports
4 our $VERSION = '3.15000';
4 our $VERSION = '3.17001';
55 $VERSION = eval $VERSION; # numify for warning-free dev releases
66
77 extends 'Net::Twitter::Core';
2929 $nt = Net::Identica->new(username => $user, password => $passwd);
3030
3131 $nt->update('Hello, Identica friends!');
32
33 =head1 DEPRECATED
34
35 This module is a backwards compatibility wrapper for applications that used
36 L<Net::Identica> packaged with C<Net::Twitter> versions 2.12 and earlier.
37 Instead, use L<Net::Twitter> with the C<identica> option to gain all of the new
38 features and functionality (OAuth, Search, exceptions on error, etc.).
39
40 use Net::Twitter;
41
42 # A simple, backwards compatible replacement for Net::Identica
43 my $identica = Net::Twitter->new(
44 legacy => 1,
45 identica => 1,
46 username => $username,
47 password => $password,
48 );
49
50 # A more complex object with OAuth and some optional traits
51 my $identica = Net::Twitter->new(
52 traits => [qw/API::REST API::Search OAuth InflateObjects/],
53 identica => 1,
54 consumer_key => $consumer_key,
55 consumer_secret => $consumer_secret,
56 access_token => $token,
57 access_token_secret => $token_secret,
58 );
3259
3360 =head1 DESCRIPTION
3461
1717 use namespace::autoclean;
1818
1919 # use *all* digits for fBSD ports
20 our $VERSION = '3.15000';
20 our $VERSION = '3.17001';
2121
2222 $VERSION = eval $VERSION; # numify for warning-free dev releases
2323
5959 return $synthetic_args;
6060 }
6161
62 around BUILDARGS => sub {
63 my $next = shift;
64 my $class = shift;
65
66 my %options = @_ == 1 ? %{$_[0]} : @_;
67
68 if ( delete $options{identica} ) {
69 %options = (
70 apiurl => 'http://identi.ca/api',
71 searchapiurl => 'http://identi.ca/api',
72 apirealm => 'Laconica API',
73 oauth_urls => {
74 request_token_url => "https://identi.ca/api/oauth/request_token",
75 authentication_url => "https://identi.ca/api/oauth/authenticate",
76 authorization_url => "https://identi.ca/api/oauth/authorize",
77 access_token_url => "https://identi.ca/api/oauth/access_token",
78 xauth_url => "https://identi.ca/api/oauth/access_token",
79 },
80 %options,
81 );
82 }
83
84 return $next->($class, \%options);
85 };
86
6287 sub BUILD {
6388 my $self = shift;
6489
11 use Moose;
22
33 # use *all* digits for fBSD ports
4 our $VERSION = '3.15000';
4 our $VERSION = '3.17001';
55 $VERSION = eval $VERSION; # numify for warning-free dev releases
66
77 extends 'Net::Twitter::Core';
1818 my $self = shift;
1919
2020 $self->{apiurl} =~ s/^http:/https:/ if $self->ssl;
21 };
22
23 around BUILDARGS => sub {
24 my $next = shift;
25 my $class = shift;
26
27 my %options = @_ == 1 ? %{$_[0]} : @_;
28
29 if ( delete $options{identica} ) {
30 %options = (
31 apiurl => 'http://identi.ca/api',
32 apirealm => 'Laconica API',
33 oauth_urls => {
34 request_token_url => "https://identi.ca/api/oauth/request_token",
35 authentication_url => "https://identi.ca/api/oauth/authenticate",
36 authorization_url => "https://identi.ca/api/oauth/authorize",
37 access_token_url => "https://identi.ca/api/oauth/access_token",
38 xauth_url => "https://identi.ca/api/oauth/access_token",
39 },
40 %options,
41 );
42 }
43
44 return $next->($class, \%options);
4521 };
4622
4723 base_url 'apiurl';
464440 returns => 'Bool',
465441 );
466442
443 twitter_api_method no_retweet_ids => (
444 description => <<'',
445 Returns an ARRAY ref of user IDs for which the authenticating user does not
446 want to receive retweets.
447
448 path => 'friendships/no_retweet_ids',
449 method => 'GET',
450 params => [],
451 required => [],
452 returns => 'ArrayRef[UserIDs]',
453 );
454
467455 twitter_api_method friends_ids => (
468456 description => <<'EOT',
469457 Returns a reference to an array of numeric IDs for every user followed the
904892 method => 'GET',
905893 params => [qw/lat long/],
906894 required => [],
895 authenticate => 0,
907896 returns => 'ArrayRef[Location]',
908897 description => <<EOT,
909898 Returns the locations with trending topic information. The response is an
925914 params => [qw/woeid/],
926915 required => [qw/woeid/],
927916 returns => 'ArrayRef[Trend]',
917 authenticate => 0,
928918 description => <<'',
929919 Returns the top 10 trending topics for a specific location. The response is an
930920 array of "trend" objects that encode the name of the trending topic, the query
936926
937927 );
938928
929 twitter_api_method trends => (
930 description => <<'',
931 Returns the top ten queries that are currently trending on Twitter. The
932 response includes the time of the request, the name of each trending topic, and
933 the url to the Twitter Search results page for that topic.
934
935 path => 'trends',
936 method => 'GET',
937 params => [qw//],
938 required => [qw//],
939 authenticate => 0,
940 returns => 'ArrayRef[Query]',
941 );
942
943 twitter_api_method trends_current => (
944 description => <<'',
945 Returns the current top ten trending topics on Twitter. The response includes
946 the time of the request, the name of each trending topic, and query used on
947 Twitter Search results page for that topic.
948
949 path => 'trends/current',
950 method => 'GET',
951 params => [qw/exclude/],
952 required => [qw//],
953 authenticate => 0,
954 returns => 'HashRef',
955 );
956
957 twitter_api_method trends_daily => (
958 description => <<'',
959 Returns the top 20 trending topics for each hour in a given day.
960
961 path => 'trends/daily',
962 method => 'GET',
963 params => [qw/date exclude/],
964 required => [qw//],
965 authenticate => 0,
966 returns => 'HashRef',
967 );
968
969 twitter_api_method trends_weekly => (
970 description => <<'',
971 Returns the top 30 trending topics for each day in a given week.
972
973 path => 'trends/weekly',
974 method => 'GET',
975 params => [qw/date exclude/],
976 required => [qw//],
977 authenticate => 0,
978 returns => 'HashRef',
979 );
980
939981 twitter_api_method reverse_geocode => (
940982 path => 'geo/reverse_geocode',
941983 method => 'GET',
10851127
10861128 );
10871129
1088 # new in 3.15000 2010-10-19
1130 # new in 3.17001 2010-10-19
10891131
10901132 twitter_api_method account_totals => (
10911133 path => 'account/totals',
00 package Net::Twitter::Role::API::Search::Trends;
1
21 use Moose::Role;
3 use Net::Twitter::API;
4
5 has search_trends_api_url => ( isa => 'Str', is => 'rw', default => 'http://api.twitter.com/1' );
62
73 after BUILD => sub {
84 my $self = shift;
95
10 $self->{search_trends_api_url} =~ s/^http:/https:/ if $self->ssl;
6 unless ( $self->can('trends') || $ENV{NET_TWITTER_NO_TRENDS_WARNING} ) {
7 warn <<EOT;
8 The "trends" methods have been moved to the API::REST trait. This warning
9 will be removed in a future release. You can supress it by:
10
11 - including the API::REST trait
12 - or setting the environment variable NET_TWITTER_NO_TRENDS_WARNING=1
13 EOT
14 }
1115 };
12
13 base_url 'search_trends_api_url';
14 authenticate 0;
15
16 twitter_api_method trends => (
17 description => <<'',
18 Returns the top ten queries that are currently trending on Twitter. The
19 response includes the time of the request, the name of each trending topic, and
20 the url to the Twitter Search results page for that topic.
21
22 path => 'trends',
23 method => 'GET',
24 params => [qw//],
25 required => [qw//],
26 returns => 'ArrayRef[Query]',
27 );
28
29 twitter_api_method trends_current => (
30 description => <<'',
31 Returns the current top ten trending topics on Twitter. The response includes
32 the time of the request, the name of each trending topic, and query used on
33 Twitter Search results page for that topic.
34
35 path => 'trends/current',
36 method => 'GET',
37 params => [qw/exclude/],
38 required => [qw//],
39 returns => 'HashRef',
40 );
41
42 twitter_api_method trends_daily => (
43 description => <<'',
44 Returns the top 20 trending topics for each hour in a given day.
45
46 path => 'trends/daily',
47 method => 'GET',
48 params => [qw/date exclude/],
49 required => [qw//],
50 returns => 'HashRef',
51 );
52
53 twitter_api_method trends_weekly => (
54 description => <<'',
55 Returns the top 30 trending topics for each day in a given week.
56
57 path => 'trends/weekly',
58 method => 'GET',
59 params => [qw/date exclude/],
60 required => [qw//],
61 returns => 'HashRef',
62 );
6316
6417 1;
6518
6720
6821 =head1 NAME
6922
70 Net::Twitter::Role::API::Search::Trends - A definition of the Twitter Search Trends API as a Moose role
23 Net::Twitter::Role::API::Search::Trends - DEPRECATED: use API::REST
7124
7225 =head1 SYNOPSIS
7326
74 package My::Twitter;
75 use Moose;
76 with 'Net::Twitter::API::Search';
27 my $nt = Net::Twitter->new(taits => [qw/API::Search API::REST/], ...);
7728
7829 =head1 DESCRIPTION
7930
80 B<Net::Twitter::Role::API::Search::Trends> provides definitions for all the
81 Twitter Search Trends API methods. You probably don't want to use it directly.
82 It is included when you use C<Search::API>. The trends methods were factored
83 out into their own class when Twitter changed the base URL for trends so that
84 it differs from search.
31 The C<trends> methods have been move to the C<API::REST> trait.
8532
8633 =head1 AUTHOR
8734
3333
3434 path => 'search',
3535 method => 'GET',
36 params => [qw/q callback lang rpp page since_id geocode show_user/],
36 params => [qw/q callback lang locale rpp page since_id until geocode show_user result_type/],
3737 required => [qw/q/],
3838 returns => 'HashRef',
3939 );
0 package Net::Twitter::Role::AutoCursor;
1 use MooseX::Role::Parameterized;
2
3 parameter max_calls => isa => 'Int', default => 16;
4 parameter array_accessor => isa => 'Str', default => 'ids';
5 parameter force_cursor => isa => 'Bool', default => 0;
6 parameter methods => isa => 'ArrayRef[Str]', default => sub { [qw/friends_ids followers_ids/] };
7
8 role {
9 my $p = shift;
10
11 requires @{$p->methods};
12
13 my $around = sub {
14 my $orig = shift;
15 my $self = shift;
16
17 my $args = ref $_[-1] eq 'HASH' ? pop : {};
18 $args->{id} = shift if @_;
19
20 $args->{cursor} = -1 if !exists $args->{cursor} && $p->force_cursor;
21
22 my $max_calls = delete $args->{max_calls} || $p->max_calls;
23
24 my $calls = 0;
25 my $results;
26 if ( !exists $args->{cursor} ) {
27 my $r = $orig->($self, $args);
28 ++$calls;
29 if ( ref $r eq 'HASH' ) {
30 # If Twitter forces a cursored call, we'll get a HASH instead of an ARRAY
31 $results = $r->{$p->array_accessor};
32 $args->{cursor} = $r->{next_cursor};
33 }
34 else {
35 $results = $r;
36 }
37 }
38
39 while ( $args->{cursor} && $calls++ < $max_calls ) {
40 my $r = $orig->($self, $args);
41 push @$results, @{$r->{$p->array_accessor}};
42 $args->{cursor} = $r->{next_cursor};
43 }
44
45 return $results;
46 };
47
48 around $_, $around for @{$p->methods};
49 };
50
51 1;
52
53 __END__
54
55 =head1 NAME
56
57 Net::Twitter::Role::AutoCursor
58
59 =head1 SYNOPSIS
60
61 use Net::Twitter;
62 my $nt = Net::Twitter->new(
63 traits => [qw/AutoCursor API::REST RetryOnError OAuth/],
64 # additional ags...
65 );
66
67 # Get friends_ids or followers_ids without worrying about cursors
68 my $ids = $nt->followers_ids;
69
70 my $nt = Net::Twitter->new(
71 traits => [
72 qw/API::REST RetryOnError OAuth/
73 AutoCursor => { max_calls => 32 },
74 AutoCursor => {
75 max_calls => 4,
76 force_cursor => 1,
77 array_accessor => 'users',
78 methods => [qw/friends followers/],
79 },
80 ],
81 # additional args
82 );
83
84 # works with any Twitter call that takes a cursor parameter
85 my $friends = $nt->friends;
86
87 =head1 DESCRIPTION
88
89 On 25-Mar-2011, Twitter announced a change to C<friends_ids> and
90 C<followers_ids> API methods:
91
92 [Soon] followers/ids and friends/ids is being updated to set the cursor to -1
93 if it isn't supplied during the request. This changes the default response
94 format
95
96 This will break a lot of existing code. The C<AutoCursor> trait was created to
97 help users transition to cursor based access for these methods.
98
99 With default parameters, the C<AutoCursor> trait attempts a non-cursored call
100 for C<friends_ids> and C<followers_ids>. If it detects a cursored
101 response from Twitter, it continues to call the underlying Twitter API method,
102 with the next cursor, until it has received all results or 16 calls have been
103 made (yielding 80,000 results). It returns an ARRAY reference to the combined
104 results.
105
106 If the C<cursor> parameter is passed to C<friends_ids> or C<followers_ids>,
107 C<Net::Twitter> uses cursored access from the start, i.e., it does not
108 attempt an initial non-cursored call.
109
110 The C<AutoCursor> trait is parameterized, allowing it to work with any Twitter
111 API method that expects cursors, returning combined results for up to the
112 maximum number of calls specified.
113
114 C<AutoCursor> can be applied multiple times to handle different sets of API
115 methods.
116
117 =head1 PARAMETERS
118
119 =over 4
120
121 =item max_calls
122
123 An integer specifying the maximum number of API calls to make. Default is 16.
124
125 C<max_calls> can be overridden on a per-call basis by passing a C<max_calls>
126 argument to the API method.
127
128 =item force_cursor
129
130 If true, when the caller does not provide a C<cursor> parameter, C<AutoCursor>
131 will add one with value -1. Default is 0.
132
133 =item array_accessor
134
135 The name of the HASH key used to access the ARRAY ref of results in the data
136 structure returned by Twitter. Default is C<ids>.
137
138 =item methods
139
140 A reference to an ARRAY containing the names of Twitter API methods to which
141 C<AutoCursor> will be applied.
142
143 =back
144
145 =head1 AUTHOR
146
147 Marc Mims <marc@questright.com>
148
149 =head1 COPYRIGHT
150
151 Copyright (c) 2011 Marc Mims
152
153 =head1 LICENSE
154
155 This library is free software and may be distributed under the same terms as perl itself.
156
157 =cut
158
11 use Moose;
22
33 # use *all* digits for fBSD ports
4 our $VERSION = '3.15000';
4 our $VERSION = '3.17001';
55 $VERSION = eval $VERSION; # numify for warning-free dev releases
66
77 extends 'Net::Twitter::Core';
11 use Moose;
22 use Carp;
33 use Net::Twitter::Core;
4 use Digest::SHA1 qw/sha1_hex/;
45
56 use namespace::autoclean;
67
1011 );
1112
1213 # use *all* digits for fBSD ports
13 our $VERSION = '3.15000';
14 our $VERSION = '3.17001';
1415
1516 $VERSION = eval $VERSION; # numify for warning-free dev releases
1617
3839
3940 sub _resolve_traits {
4041 my ($class, @traits) = @_;
42
4143 return map {
42 my $transformed = $class->_transform_trait($_);
43 Class::MOP::load_class($transformed);
44 $transformed;
44 unless ( ref ) {
45 $_ = $class->_transform_trait($_);
46 Class::MOP::load_class($_);
47 }
48 $_;
4549 } @traits;
4650 }
4751
5559 sub _create_anon_class {
5660 my ($superclasses, $traits, $immutable, $package) = @_;
5761
62 # Do we already have a meta class?
63 return $package->meta if $package->can('meta');
64
5865 my $meta;
5966 $meta = Net::Twitter::Core->meta->create_anon_class(
6067 superclasses => $superclasses,
6168 roles => $traits,
6269 methods => { meta => sub { $meta }, isa => \&_isa },
63 cache => 1,
70 cache => 0,
6471 package => $package,
6572 );
6673 $meta->make_immutable(inline_constructor => $immutable);
6774
6875 return $meta;
76 }
77
78 {
79 my $serial_number = 0;
80 my %serial_for_params;
81
82 sub _name_for_anon_class {
83 my @t = @{$_[0]};
84
85 my @comps;
86 while ( @t ) {
87 my $t = shift @t;
88 if ( ref $t[0] eq 'HASH' ) {
89 my $params = shift @t;
90 my $sig = sha1_hex(JSON::Any->to_json($params));
91 my $sn = $serial_for_params{$sig} ||= ++$serial_number;
92 $t .= "_$sn";
93 }
94 $t =~ s/(?:::|\W)/_/g;
95 push @comps, $t;
96 }
97
98 return __PACKAGE__ . '::' . join '__', 'with', sort @comps;
99 }
69100 }
70101
71102 sub new {
89120 # ensure we have the OAuth trait if we have a consumer key
90121 $traits = [ (grep $_ ne 'OAuth', @$traits), 'OAuth' ] if $args{consumer_key};
91122
92 my $package_suffix = 'with__' . join '__',
93 map { (my $part = $_) =~ s/::/_/g; $part =~ s/\W//; $part } sort @$traits;
123 # create a unique name for the created class based on trait names and parameters
124 my $anon_class_name = _name_for_anon_class($traits);
94125
95126 $traits = [ $class->_resolve_traits(@$traits) ];
96127
97128 my $superclasses = [ 'Net::Twitter::Core' ];
98 my $meta = _create_anon_class($superclasses, $traits, 1, __PACKAGE__ . '::' . $package_suffix);
129 my $meta = _create_anon_class($superclasses, $traits, 1, $anon_class_name);
99130
100131 # create a Net::Twitter::Core object with roles applied
101132 my $new = $meta->name->new(%args);
104135 if ( $class ne __PACKAGE__ ) {
105136 unshift @$superclasses, $class;
106137 my $final_meta = _create_anon_class(
107 $superclasses, $traits, 0, join '::', $class, __PACKAGE__, $package_suffix
138 $superclasses, $traits, 0, join '::', $class, $anon_class_name
108139 );
109140 bless $new, $final_meta->name;
110141 }
33
44 =head1 VERSION
55
6 This document describes Net::Twitter version 3.15000
6 This document describes Net::Twitter version 3.17001
77
88 =head1 SYNOPSIS
99
123123 Provides support for the TwitterVision API. See
124124 L<http://twittervision.com/api.html>.
125125
126 =item WrapError
127
128 C<Net::Twitter> normally throws exceptions on error. When this trait is
129 included, C<Net::Twitter> returns undef when a method fails and makes the
130 error available through method C<get_error>. This is the way all errors were
131 handled in Net::Twitter versions prior to version 3.00.
132
133 =item OAuth
134
135 The C<OAuth> trait provides OAuth authentication rather than the default Basic
136 Authentication for Twitter API method calls. See the L</Authentication>
137 section and L<Net::Twitter::Role::OAuth> for full documentation.
126 =item AutoCursor
127
128 C<AutoCursor> is a parameterized trait that provides an automatic loop for
129 cursored calls, returning an ARRAY reference to the combined results. By
130 default, it handles C<friends_ids> and C<followers_ids>. See
131 L<Net::Twitter::Role::AutoCursor> for details.
138132
139133 =item InflateObjects
140134
161155 # etc.
162156 print $r->relative_created_at;
163157
164 =item RateLimit
165
166 The C<RateLimit> trait adds utility methods that return information about the
167 current rate limit status. See L<Net::Twitter::Role::RateLimit> for details.
168
169158 =item Legacy
170159
171160 This trait provides backwards compatibility to C<Net::Twitter> versions prior
178167 option is not specified. This ensures backwards compatibility for existing
179168 applications using C<Net::Twitter> versions prior to 3.00. See section
180169 L</LEGACY COMPATIBILITY> for more details.
170
171 =item OAuth
172
173 The C<OAuth> trait provides OAuth authentication rather than the default Basic
174 Authentication for Twitter API method calls. See the L</Authentication>
175 section and L<Net::Twitter::Role::OAuth> for full documentation.
176
177 =item RateLimit
178
179 The C<RateLimit> trait adds utility methods that return information about the
180 current rate limit status. See L<Net::Twitter::Role::RateLimit> for details.
181
182 =item RetryOnError
183
184 The C<RetryOnError> trait automatically retries Twitter API calls with
185 temporary failures. See L<Net::Twitter::Role::RetryOnError> for details.
186
187 =item WrapError
188
189 C<Net::Twitter> normally throws exceptions on error. When this trait is
190 included, C<Net::Twitter> returns undef when a method fails and makes the
191 error available through method C<get_error>. This is the way all errors were
192 handled in Net::Twitter versions prior to version 3.00.
181193
182194 =back
183195
13061318
13071319 Returns: DirectMessage
13081320
1321 =item B<no_retweet_ids>
1322
1323
1324
1325 =over 4
1326
1327 =item Parameters: I<none>
1328
1329 =item Required: I<none>
1330
1331 =back
1332
1333 Returns an ARRAY ref of user IDs for which the authenticating user does not
1334 want to receive retweets.
1335
1336
1337 Returns: ArrayRef[UserIDs]
1338
13091339 =item B<public_timeline>
13101340
13111341
18111841
18121842 Returns: Str
18131843
1844 =item B<trends>
1845
1846
1847
1848 =over 4
1849
1850 =item Parameters: I<none>
1851
1852 =item Required: I<none>
1853
1854 =back
1855
1856 Returns the top ten queries that are currently trending on Twitter. The
1857 response includes the time of the request, the name of each trending topic, and
1858 the url to the Twitter Search results page for that topic.
1859
1860
1861 Returns: ArrayRef[Query]
1862
18141863 =item B<trends_available>
18151864
18161865
18361885
18371886
18381887 Returns: ArrayRef[Location]
1888
1889 =item B<trends_current>
1890
1891 =item B<trends_current(exclude)>
1892
1893
1894
1895 =over 4
1896
1897 =item Parameters: exclude
1898
1899 =item Required: I<none>
1900
1901 =back
1902
1903 Returns the current top ten trending topics on Twitter. The response includes
1904 the time of the request, the name of each trending topic, and query used on
1905 Twitter Search results page for that topic.
1906
1907
1908 Returns: HashRef
1909
1910 =item B<trends_daily>
1911
1912
1913
1914 =over 4
1915
1916 =item Parameters: date, exclude
1917
1918 =item Required: I<none>
1919
1920 =back
1921
1922 Returns the top 20 trending topics for each hour in a given day.
1923
1924
1925 Returns: HashRef
18391926
18401927 =item B<trends_location>
18411928
18621949
18631950 Returns: ArrayRef[Trend]
18641951
1952 =item B<trends_weekly>
1953
1954
1955
1956 =over 4
1957
1958 =item Parameters: date, exclude
1959
1960 =item Required: I<none>
1961
1962 =back
1963
1964 Returns the top 30 trending topics for each day in a given week.
1965
1966
1967 Returns: HashRef
1968
18651969 =item B<update>
18661970
18671971 =item B<update(status)>
21812285
21822286 =over 4
21832287
2184 =item Parameters: q, callback, lang, rpp, page, since_id, geocode, show_user
2288 =item Parameters: q, callback, lang, locale, rpp, page, since_id, until, geocode, show_user, result_type
21852289
21862290 =item Required: q
21872291
21952299 for my $status ( @{$r->{results}} ) {
21962300 print "$status->{text}\n";
21972301 }
2198
2199
2200 Returns: HashRef
2201
2202 =item B<trends>
2203
2204
2205
2206 =over 4
2207
2208 =item Parameters: I<none>
2209
2210 =item Required: I<none>
2211
2212 =back
2213
2214 Returns the top ten queries that are currently trending on Twitter. The
2215 response includes the time of the request, the name of each trending topic, and
2216 the url to the Twitter Search results page for that topic.
2217
2218
2219 Returns: ArrayRef[Query]
2220
2221 =item B<trends_current>
2222
2223 =item B<trends_current(exclude)>
2224
2225
2226
2227 =over 4
2228
2229 =item Parameters: exclude
2230
2231 =item Required: I<none>
2232
2233 =back
2234
2235 Returns the current top ten trending topics on Twitter. The response includes
2236 the time of the request, the name of each trending topic, and query used on
2237 Twitter Search results page for that topic.
2238
2239
2240 Returns: HashRef
2241
2242 =item B<trends_daily>
2243
2244
2245
2246 =over 4
2247
2248 =item Parameters: date, exclude
2249
2250 =item Required: I<none>
2251
2252 =back
2253
2254 Returns the top 20 trending topics for each hour in a given day.
2255
2256
2257 Returns: HashRef
2258
2259 =item B<trends_weekly>
2260
2261
2262
2263 =over 4
2264
2265 =item Parameters: date, exclude
2266
2267 =item Required: I<none>
2268
2269 =back
2270
2271 Returns the top 30 trending topics for each day in a given week.
22722302
22732303
22742304 Returns: HashRef
123123 Provides support for the TwitterVision API. See
124124 L<http://twittervision.com/api.html>.
125125
126 =item WrapError
127
128 C<Net::Twitter> normally throws exceptions on error. When this trait is
129 included, C<Net::Twitter> returns undef when a method fails and makes the
130 error available through method C<get_error>. This is the way all errors were
131 handled in Net::Twitter versions prior to version 3.00.
132
133 =item OAuth
134
135 The C<OAuth> trait provides OAuth authentication rather than the default Basic
136 Authentication for Twitter API method calls. See the L</Authentication>
137 section and L<Net::Twitter::Role::OAuth> for full documentation.
126 =item AutoCursor
127
128 C<AutoCursor> is a parameterized trait that provides an automatic loop for
129 cursored calls, returning an ARRAY reference to the combined results. By
130 default, it handles C<friends_ids> and C<followers_ids>. See
131 L<Net::Twitter::Role::AutoCursor> for details.
138132
139133 =item InflateObjects
140134
161155 # etc.
162156 print $r->relative_created_at;
163157
164 =item RateLimit
165
166 The C<RateLimit> trait adds utility methods that return information about the
167 current rate limit status. See L<Net::Twitter::Role::RateLimit> for details.
168
169158 =item Legacy
170159
171160 This trait provides backwards compatibility to C<Net::Twitter> versions prior
178167 option is not specified. This ensures backwards compatibility for existing
179168 applications using C<Net::Twitter> versions prior to 3.00. See section
180169 L</LEGACY COMPATIBILITY> for more details.
170
171 =item OAuth
172
173 The C<OAuth> trait provides OAuth authentication rather than the default Basic
174 Authentication for Twitter API method calls. See the L</Authentication>
175 section and L<Net::Twitter::Role::OAuth> for full documentation.
176
177 =item RateLimit
178
179 The C<RateLimit> trait adds utility methods that return information about the
180 current rate limit status. See L<Net::Twitter::Role::RateLimit> for details.
181
182 =item RetryOnError
183
184 The C<RetryOnError> trait automatically retries Twitter API calls with
185 temporary failures. See L<Net::Twitter::Role::RetryOnError> for details.
186
187 =item WrapError
188
189 C<Net::Twitter> normally throws exceptions on error. When this trait is
190 included, C<Net::Twitter> returns undef when a method fails and makes the
191 error available through method C<get_error>. This is the way all errors were
192 handled in Net::Twitter versions prior to version 3.00.
181193
182194 =back
183195
11 use warnings;
22 use strict;
33 use Test::More;
4 use Test::Exception;
4 use Test::Fatal;
55 use lib qw(t/lib);
66 use Net::Twitter;
77
1919 my $t = TestUA->new($nt->ua);
2020
2121 # things that should fail
22 throws_ok { $nt->relationship_exists(qw/one two three/) } qr/expected 2 args/, 'too many args';
23 throws_ok {
24 Net::Twitter->new(useragent_class => 'NoSuchModule::Test7701')->verify_credentials
25 } qr/Can't locate NoSuchModule/, 'bad useragent_class';
22 like exception { $nt->relationship_exists(qw/one two three/) }, qr/expected 2 args/, 'too many args';
23 like exception { Net::Twitter->new(useragent_class => 'NoSuchModule::Test7701')->verify_credentials },
24 qr/Can't locate NoSuchModule/, 'bad useragent_class';
2625
2726 exit 0;
11 use Carp;
22 use strict;
33 use Test::More;
4 use Test::Exception;
4 use Test::Fatal;
55 use lib qw(t/lib);
66
77 {
3838 my $r;
3939
4040 # back compat: 1.23 accepts scalar args
41 lives_ok { $r = $nt->relationship_exists('homer', 'marge') } 'relationship_exists scalar args';
41 is exception { $r = $nt->relationship_exists('homer', 'marge') }, undef, 'relationship_exists scalar args';
4242
4343 ok $r = $nt->relationship_exists({ user_a => 'homer', user_b => 'marge' }),
4444 'relationship_exists hashref';
9292 is $t->request->uri->scheme, 'https', 'ssl used for Lists';
9393
9494 ### v3.10001 ### netrc used $self->apiurl, which is only available via the API::REST trait
95 lives_ok { Net::Twitter->new(netrc => 1, traits => [qw/API::Lists/]) }
96 'netrc with API::Lists lives';
95 is exception { Net::Twitter->new(netrc => 1, traits => [qw/API::Lists/]) }, undef, 'netrc with API::Lists lives';
9796 ### v3.11004 ### single array ref arg to update_profile_image not proprerly handled
9897 $r = $nt->update_profile_image([ undef, 'my_mug.jpg', Content_Type => 'image/jpeg', Content => '' ]);
9998 is $t->request->content_type, 'multipart/form-data', 'multipart/form-data';
33 use strict;
44
55 use Test::More tests => 3;
6 use Test::Exception;
6 use Test::Fatal;
77
88 use_ok 'Net::Twitter';
99
1010 my $nt;
11 lives_ok { $nt = Net::Twitter->new(useragent_args => { timeout => 20 }) }
11 is exception { $nt = Net::Twitter->new(useragent_args => { timeout => 20 }) }, undef,
1212 'object creation with useragent_args';
1313
1414 is $nt->ua->timeout, 20, 'useragent_args applied';
88 eval 'use TestUA';
99 plan skip_all => 'LWP::UserAgent 5.819 required for tests' if $@;
1010
11 plan tests => 4;
11 plan tests => 5;
1212
1313 use_ok 'Net::Twitter';
1414
15 my $nt = Net::Twitter->new(legacy => 0, identica => 1, username => 'me', password => 'secret');
16 my $t = TestUA->new($nt->ua);
15 {
16 my $nt = Net::Twitter->new(legacy => 0, identica => 1, username => 'me', password => 'secret');
17 my $t = TestUA->new($nt->ua);
1718
18 $t->response->content('"true"');
19 my $r = $nt->follows('night', 'day');
20 ok $r, 'string "true" is true';
19 $t->response->content('"true"');
20 my $r = $nt->follows('night', 'day');
21 ok $r, 'string "true" is true';
2122
22 $t->response->content('"false"');
23 $r = $nt->follows('night', 'day');
24 ok !$r, 'string "false" is false';
23 $t->response->content('"false"');
24 $r = $nt->follows('night', 'day');
25 ok !$r, 'string "false" is false';
2526
2627 # and when they finally get it right:
27 $t->response->content('"true"');
28 $r = $nt->follows('night', 'day');
29 ok $r, 'bool true is true';
28 $t->response->content('"true"');
29 $r = $nt->follows('night', 'day');
30 ok $r, 'bool true is true';
31 }
32
33 {
34 my $nt = Net::Twitter->new(traits => [qw/API::REST API::Search/], identica => 1);
35 like $nt->searchapiurl, qr/identi\.ca/, 'use identica url for search';
36 }
1010
1111 use Net::Twitter;
1212
13 my $nt = Net::Twitter->new(traits => [qw/API::Search/]);
13 my $nt = Net::Twitter->new(traits => [qw/API::Search API::REST/]);
1414
1515 my $request;
1616 my %args;
11 use warnings;
22 use strict;
33 use Test::More;
4 use Test::Exception;
4 use Test::Fatal;
55 use lib qw(t/lib);
66 use Net::Twitter;
77
1616 $nt = Net::Twitter->new(legacy => 0);
1717 my $t = TestUA->new($nt->ua);
1818
19 lives_ok { $nt->user_timeline } "lives without credentials";
19 is exception { $nt->user_timeline }, undef, "lives without credentials";
2020 ok !$t->request->header('Authorization'), "no auth header without credentials";
2121
2222 $nt->credentials(homer => 'doh!');
23 lives_ok { $nt->user_timeline } "lives with credentials";
23 is exception { $nt->user_timeline }, undef, "lives with credentials";
2424 like $t->request->header('Authorization'), qr/Basic/, "has Basic Auth header";
2525
2626 $nt->public_timeline;
4545 );
4646 $t = TestUA->new($nt->ua);
4747
48 lives_ok { $nt->user_timeline } "lives without oauth tokens";
48 is exception { $nt->user_timeline }, undef, "lives without oauth tokens";
4949 ok !$t->request->header('Authorization'), "no auth header without access tokens";
5050
5151 $nt->access_token('1234');
5252 $nt->access_token_secret('5678');
53 lives_ok { $nt->user_timeline } "lives with access tokens";
53 is exception { $nt->user_timeline }, undef, "lives with access tokens";
11 use warnings;
22 use strict;
33 use Test::More;
4 use Test::Exception;
4 use Test::Fatal;
55 use lib qw(t/lib);
66 use Net::Twitter;
77
88 eval 'use TestUA';
99 plan skip_all => 'LWP::UserAgent 5.819 required for tests' if $@;
10
11 plan tests => 11;
1210
1311 my $nt = Net::Twitter->new(
1412 traits => [qw/API::REST/],
3432 fail $message;
3533 }
3634
37 dies_ok { $nt->destroy_direct_message(456) } 'TwitterException';
38 my $e = $@;
39 isa_ok $e, 'Net::Twitter::Error';
40 like $e, qr/No direct message/, 'error stringifies';
41 is $e->http_response->code, 404, "respose code";
42 is $e->code, 404, 'http_response handles code';
43 like $e->twitter_error->{request}, qr/456.json/, 'twitter_error request';
44 is $e, $e->error, 'stringifies to $@->error';
45
46
35 {
36 my $e = exception { $nt->destroy_direct_message(456) };
37 isa_ok $e, 'Net::Twitter::Error';
38 like $e, qr/No direct message/, 'error stringifies';
39 is $e->http_response->code, 404, "respose code";
40 is $e->code, 404, 'http_response handles code';
41 like $e->twitter_error->{request}, qr/456.json/, 'twitter_error request';
42 is $e, $e->error, 'stringifies to $@->error';
43 }
4744
4845 # simulate a 500 response returned by LWP::UserAgent when it can't make a connection
4946 $response = HTTP::Response->new(500, "Can't connect to api.twitter.com:80");
5047 $response->content("<html>foo</html>");
5148 $t->response($response);
5249
53 dies_ok { $nt->friends_timeline({ since_id => 500_000_000 }) } 'HttpException';
54 $e = $@;
55 isa_ok $e, 'Net::Twitter::Error';
56 like $e->http_response->content, qr/html/, 'html content';
50 {
51 my $e = exception { $nt->friends_timeline({ since_id => 500_000_000 }) };
52 isa_ok $e, 'Net::Twitter::Error';
53 like $e->http_response->content, qr/html/, 'html content';
54 }
5755
58 exit 0;
56 done_testing;
00 #!perl
11 use warnings;
22 use strict;
3 use Test::Exception;
3 use Test::Fatal;
44 use Test::More;
55 use lib qw(t/lib);
66
2222
2323 $t->response(HTTP::Response->new(500, $msg));
2424
25 lives_ok { $r = $nt->public_timeline } 'exception trapped';
25 is exception { $r = $nt->public_timeline }, undef, 'exception trapped';
2626 is $nt->http_message, $msg, 'http_message';
2727 isa_ok $nt->get_error, 'HASH', 'get_error returns a HASH ref';
2828 ok !defined $r, 'result is undef';
00 #!perl
11 use warnings;
22 use strict;
3 use Test::Exception;
3 use Test::Fatal;
44 use Test::More;
55 use lib qw(t/lib);
66
2525
2626 $t->response(HTTP::Response->new(500, $msg));
2727
28 lives_ok { $nt->public_timeline } 'exception trapped';
28 is exception { $nt->public_timeline }, undef, 'exception trapped';
2929 is $nt->http_message, $msg, 'http_message';
3030
3131 exit 0;
5757 }
5858 catch { pass $test };
5959
60 $nt = Net::Twitter->new(traits => [qw/API::Search/]);
60 $nt = Net::Twitter->new(traits => [qw/API::Search API::REST/]);
6161 $nt->ua->add_handler(request_send => sub {
6262 my $res = HTTP::Response->new(200);
6363 $res->content('{"test":"done"}');
1919 API
2020 APIs
2121 Akira
22 AutoCursor
2223 BasicUser
2324 CPAN
2425 DateTime
4445 Prather
4546 RateLimit
4647 RateLimitStatus
48 RetryOnError
4749 Retweets
4850 SMS
4951 SSL
7880 oauth
7981 ok
8082 online
83 parameterized
8184 params
8285 perigrin
8386 Pecorella
0 #!perl
1 use warnings;
2 use strict;
3 use Test::More;
4 use Net::Twitter;
5 use JSON::Any;
6 use HTTP::Response;
7
8 my $json_result = JSON::Any->to_json({ ids => ['test'], next_cursor => 1 });
9 sub mock_ua {
10 my $nt = shift;
11
12
13 $nt->ua->add_handler(request_send => sub {
14 my $resp = HTTP::Response->new(200);
15 $resp->content($json_result);
16 return $resp;
17 });
18 }
19
20 {
21 my $nt_with_max_calls_2 = Net::Twitter->new(traits => ['API::REST', AutoCursor => { max_calls => 2 }]);
22 my $class_for_max_calls_2 = ref $nt_with_max_calls_2;
23
24 my $nt_with_max_calls_4 = Net::Twitter->new(traits => ['API::REST', AutoCursor => { max_calls => 4 }]);
25 my $class_for_max_calls_4 = ref $nt_with_max_calls_4;
26
27 my $json_result = JSON::Any->to_json({ ids => ['test'], next_cursor => 1 });
28
29 mock_ua($_) for $nt_with_max_calls_2, $nt_with_max_calls_4;
30
31 my $r = $nt_with_max_calls_2->friends_ids({ cursor => -1 });
32 is scalar @$r, 2, 'max_calls => 2';
33
34 $r = $nt_with_max_calls_4->friends_ids({ cursor => -1 });
35 is scalar @$r, 4, 'max_calls => 4';
36
37 $r = $nt_with_max_calls_4->followers_ids({ cursor => -1, max_calls => 10 });
38 is scalar @$r, 10, 'max_calls per call override';
39
40 my $nt = Net::Twitter->new(traits => ['API::REST', AutoCursor => { max_calls => 2 }]);
41 mock_ua($nt);
42 is ref $nt, $class_for_max_calls_2, 'clone max_calls => 2, class name';
43 $r = $nt->friends_ids({ cursor => -1 });
44 is scalar @$r, 2, 'cloned max_calls => 2';
45
46 $nt = Net::Twitter->new(traits => ['API::REST', AutoCursor => { max_calls => 4 }]);
47 mock_ua($nt);
48 is ref $nt, $class_for_max_calls_4, 'clone max_calls => 4, class name';
49 $r = $nt->friends_ids({ cursor => -1 });
50 is scalar @$r, 4, 'cloned max_calls => 4';
51 }
52
53 done_testing;