line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Twitter::Role::AutoCursor; |
2
|
|
|
|
|
|
|
$Net::Twitter::Role::AutoCursor::VERSION = '4.01010'; |
3
|
1
|
|
|
1
|
|
991
|
use MooseX::Role::Parameterized; |
|
1
|
|
|
|
|
34982
|
|
|
1
|
|
|
|
|
4
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
parameter max_calls => isa => 'Int', default => 16; |
6
|
|
|
|
|
|
|
parameter array_accessor => isa => 'Str', default => 'ids'; |
7
|
|
|
|
|
|
|
parameter force_cursor => isa => 'Bool', default => 0; |
8
|
|
|
|
|
|
|
parameter methods => isa => 'ArrayRef[Str]', default => sub { [qw/friends_ids followers_ids/] }; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
role { |
11
|
|
|
|
|
|
|
my $p = shift; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
requires @{$p->methods}; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $around = sub { |
16
|
|
|
|
|
|
|
my $orig = shift; |
17
|
|
|
|
|
|
|
my $self = shift; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $args = ref $_[-1] eq ref {} ? pop : {}; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# backwards compat: all synthetic args use dash (-) prefix, now |
22
|
|
|
|
|
|
|
for ( qw/force_cursor max_calls/ ) { |
23
|
|
|
|
|
|
|
$args->{"-$_"} = delete $args->{$_} if exists $args->{$_}; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# no change in behavior if the user passed a cursor |
27
|
|
|
|
|
|
|
return $self->$orig(@_, $args) if exists $args->{cursor}; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$args->{id} = shift if @_; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $force_cursor = exists $args->{-force_cursor} ? $args->{-force_cursor} : $p->force_cursor; |
32
|
|
|
|
|
|
|
$args->{cursor} = -1 if !exists $args->{cursor} && $force_cursor; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $max_calls = exists $args->{-max_calls} ? $args->{-max_calls} : $p->max_calls; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my $calls = 0; |
37
|
|
|
|
|
|
|
my $results; |
38
|
|
|
|
|
|
|
if ( !exists $args->{cursor} ) { |
39
|
|
|
|
|
|
|
# try the old style, non-cursored call |
40
|
|
|
|
|
|
|
my $r = $orig->($self, $args); |
41
|
|
|
|
|
|
|
return $r if ref $r eq ref []; |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
++$calls; |
44
|
|
|
|
|
|
|
# If Twitter forces a cursored call, we'll get a HASH instead of an ARRAY |
45
|
|
|
|
|
|
|
$results = $r->{$p->array_accessor}; |
46
|
|
|
|
|
|
|
$args->{cursor} = $r->{next_cursor}; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
while ( $args->{cursor} && $calls++ < $max_calls ) { |
50
|
|
|
|
|
|
|
my $r = $self->$orig($args); |
51
|
|
|
|
|
|
|
push @$results, @{$r->{$p->array_accessor}}; |
52
|
|
|
|
|
|
|
$args->{cursor} = $r->{next_cursor}; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
return $results; |
56
|
|
|
|
|
|
|
}; |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
around $_, $around for @{$p->methods}; |
59
|
|
|
|
|
|
|
}; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
1; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
__END__ |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head1 NAME |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Net::Twitter::Role::AutoCursor - Help transition to cursor based access to friends_ids and followers_ids methods |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head1 VERSION |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
version 4.01010 |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head1 SYNOPSIS |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
use Net::Twitter; |
76
|
|
|
|
|
|
|
my $nt = Net::Twitter->new( |
77
|
|
|
|
|
|
|
traits => [qw/AutoCursor API::RESTv1_1 RetryOnError OAuth/], |
78
|
|
|
|
|
|
|
# additional ags... |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# Get friends_ids or followers_ids without worrying about cursors |
82
|
|
|
|
|
|
|
my $ids = $nt->followers_ids; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
my $nt = Net::Twitter->new( |
85
|
|
|
|
|
|
|
traits => [ |
86
|
|
|
|
|
|
|
qw/API::RESTv1_1 RetryOnError OAuth/ |
87
|
|
|
|
|
|
|
AutoCursor => { max_calls => 32 }, |
88
|
|
|
|
|
|
|
AutoCursor => { |
89
|
|
|
|
|
|
|
max_calls => 4, |
90
|
|
|
|
|
|
|
force_cursor => 1, |
91
|
|
|
|
|
|
|
array_accessor => 'users', |
92
|
|
|
|
|
|
|
methods => [qw/friends followers/], |
93
|
|
|
|
|
|
|
}, |
94
|
|
|
|
|
|
|
], |
95
|
|
|
|
|
|
|
# additional args |
96
|
|
|
|
|
|
|
); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# works with any Twitter call that takes a cursor parameter |
99
|
|
|
|
|
|
|
my $friends = $nt->friends; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head1 DESCRIPTION |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
On 25-Mar-2011, Twitter announced a change to C<friends_ids> and |
104
|
|
|
|
|
|
|
C<followers_ids> API methods: |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
[Soon] followers/ids and friends/ids is being updated to set the cursor to -1 |
107
|
|
|
|
|
|
|
if it isn't supplied during the request. This changes the default response |
108
|
|
|
|
|
|
|
format |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
This will break a lot of existing code. The C<AutoCursor> trait was created to |
111
|
|
|
|
|
|
|
help users transition to cursor based access for these methods. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
With default parameters, the C<AutoCursor> trait attempts a non-cursored call |
114
|
|
|
|
|
|
|
for C<friends_ids> and C<followers_ids>. If it detects a cursored |
115
|
|
|
|
|
|
|
response from Twitter, it continues to call the underlying Twitter API method, |
116
|
|
|
|
|
|
|
with the next cursor, until it has received all results or 16 calls have been |
117
|
|
|
|
|
|
|
made (yielding 80,000 results). It returns an ARRAY reference to the combined |
118
|
|
|
|
|
|
|
results. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
If the C<cursor> parameter is passed to C<friends_ids> or C<followers_ids>, |
121
|
|
|
|
|
|
|
C<Net::Twitter> assumes the user is handling cursoring and does not modify |
122
|
|
|
|
|
|
|
behavior or results. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
The C<AutoCursor> trait is parameterized, allowing it to work with any Twitter |
125
|
|
|
|
|
|
|
API method that expects cursors, returning combined results for up to the |
126
|
|
|
|
|
|
|
maximum number of calls specified. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
C<AutoCursor> can be applied multiple times to handle different sets of API |
129
|
|
|
|
|
|
|
methods. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=head1 PARAMETERS |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=over 4 |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item max_calls |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
An integer specifying the maximum number of API calls to make. Default is 16. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
C<max_calls> can be overridden on a per-call basis by passing a C<max_calls> |
140
|
|
|
|
|
|
|
argument to the API method. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=item force_cursor |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
If true, when the caller does not provide a C<cursor> parameter, C<AutoCursor> |
145
|
|
|
|
|
|
|
will use up to C<max_calls> cursored calls rather than attempting an initial |
146
|
|
|
|
|
|
|
non-cursored call. Default is 0. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item array_accessor |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
The name of the HASH key used to access the ARRAY ref of results in the data |
151
|
|
|
|
|
|
|
structure returned by Twitter. Default is C<ids>. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=item methods |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
A reference to an ARRAY containing the names of Twitter API methods to which |
156
|
|
|
|
|
|
|
C<AutoCursor> will be applied. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=back |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 METHOD CALLS |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Synthetic parameter C<-max_calls> can be passed for individual method calls |
163
|
|
|
|
|
|
|
to override the default: |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
$r = $nt->followers_ids({ -max_calls => 200 }); # get up to 1 million ids |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Synthetic parameter C<-force_cursor> can be passed to override the |
168
|
|
|
|
|
|
|
C<force_cursor> default. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head1 AUTHOR |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Marc Mims <marc@questright.com> |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head1 COPYRIGHT |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Copyright (c) 2011 Marc Mims |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head1 LICENSE |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
This library is free software and may be distributed under the same terms as perl itself. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=cut |