twitter_friendly 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.travis.yml +41 -0
- data/Gemfile.lock +44 -5
- data/README.md +163 -11
- data/bin/test/friends_and_followers.rb +95 -0
- data/gemfiles/ar_4.2.gemfile +5 -0
- data/gemfiles/ar_5.1.gemfile +5 -0
- data/gemfiles/ar_5.2.gemfile +5 -0
- data/lib/twitter_friendly.rb +12 -0
- data/lib/twitter_friendly/cache.rb +48 -0
- data/lib/twitter_friendly/cache_key.rb +64 -0
- data/lib/twitter_friendly/caching.rb +86 -0
- data/lib/twitter_friendly/client.rb +52 -0
- data/lib/twitter_friendly/log_subscriber.rb +109 -0
- data/lib/twitter_friendly/logger.rb +18 -0
- data/lib/twitter_friendly/rate_limit.rb +81 -0
- data/lib/twitter_friendly/rest/api.rb +34 -0
- data/lib/twitter_friendly/rest/base.rb +32 -0
- data/lib/twitter_friendly/rest/collector.rb +78 -0
- data/lib/twitter_friendly/rest/favorites.rb +15 -0
- data/lib/twitter_friendly/rest/friends_and_followers.rb +64 -0
- data/lib/twitter_friendly/rest/lists.rb +22 -0
- data/lib/twitter_friendly/rest/parallel.rb +30 -0
- data/lib/twitter_friendly/rest/search.rb +16 -0
- data/lib/twitter_friendly/rest/timelines.rb +15 -0
- data/lib/twitter_friendly/rest/tweets.rb +13 -0
- data/lib/twitter_friendly/rest/users.rb +49 -0
- data/lib/twitter_friendly/rest/utils.rb +11 -0
- data/lib/twitter_friendly/serializer.rb +79 -0
- data/lib/twitter_friendly/utils.rb +6 -0
- data/lib/twitter_friendly/version.rb +1 -1
- data/twitter_friendly.gemspec +11 -2
- metadata +127 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cec5d0d0bab4de7c8cc59727c5c57ce632b76c6e40c3684a66cce539cbb509ef
|
4
|
+
data.tar.gz: d37e61958513f084b5eed73f68f9d073202dd58e774138072cb6a1b28b3e70bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 376dbce938d1e5baf735fee3ff09a869ce2b2b562c159046c1a92c37d9e5408d2f5ae4ce005f98eb62d5dbb6f10b31229b15bd402a905c949ad9adbe38aa0aae
|
7
|
+
data.tar.gz: 93f140337e9a317165f974e65a992e34a42d1f278add7add063379c882c51aeef54ccb179cef419e02ad21956f3d9aad2f370fad211d5bb680ab587fa8298eeb
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
|
4
|
+
# For ruby compatibility, we test the highest and lowest minor versions only.
|
5
|
+
# For example, if our gemspec says `required_ruby_version = ">= 2.3.0"`, and
|
6
|
+
# ruby 2.5.0 has just been released, then we test 2.3 and 2.5, but not 2.4.
|
7
|
+
rvm:
|
8
|
+
- 2.3.8
|
9
|
+
- 2.4.5
|
10
|
+
- 2.5.3
|
11
|
+
|
12
|
+
env:
|
13
|
+
global:
|
14
|
+
- TRAVIS=true
|
15
|
+
|
16
|
+
# We want to use `sudo: false` because the container infrastructure is supposed
|
17
|
+
# to be faster, but Travis is having issues with containers lately ..
|
18
|
+
#
|
19
|
+
# > No output has been received in the last 10m0s
|
20
|
+
#
|
21
|
+
# .. and they recommend we use the VM infrastructure (`sudo: required`) in
|
22
|
+
# the meantime.
|
23
|
+
sudo: required
|
24
|
+
|
25
|
+
before_install:
|
26
|
+
- gem update bundler
|
27
|
+
|
28
|
+
gemfile:
|
29
|
+
- gemfiles/ar_4.2.gemfile
|
30
|
+
- gemfiles/ar_5.1.gemfile
|
31
|
+
- gemfiles/ar_5.2.gemfile
|
32
|
+
matrix:
|
33
|
+
exclude:
|
34
|
+
# optimization: don't test intermediate rubies (see above)
|
35
|
+
- rvm: 2.4.5
|
36
|
+
gemfile: gemfiles/ar_4.2.gemfile
|
37
|
+
- rvm: 2.4.5
|
38
|
+
gemfile: gemfiles/ar_5.1.gemfile
|
39
|
+
- rvm: 2.4.5
|
40
|
+
gemfile: gemfiles/ar_5.2.gemfile
|
41
|
+
fast_finish: true
|
data/Gemfile.lock
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
twitter_friendly (0.
|
4
|
+
twitter_friendly (0.2.0)
|
5
|
+
activesupport (>= 4.2, < 6.0)
|
6
|
+
oj (~> 3.7.6)
|
5
7
|
parallel (~> 1.12.1)
|
6
8
|
twitter (~> 6.2.0)
|
7
9
|
|
8
10
|
GEM
|
9
11
|
remote: https://rubygems.org/
|
10
12
|
specs:
|
13
|
+
activesupport (5.2.2)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (>= 0.7, < 2)
|
16
|
+
minitest (~> 5.1)
|
17
|
+
tzinfo (~> 1.1)
|
11
18
|
addressable (2.5.2)
|
12
19
|
public_suffix (>= 2.0.2, < 4.0)
|
13
20
|
buftok (0.2.0)
|
21
|
+
coderay (1.1.2)
|
22
|
+
concurrent-ruby (1.1.4)
|
23
|
+
diff-lcs (1.3)
|
14
24
|
domain_name (0.5.20180417)
|
15
25
|
unf (>= 0.0.5, < 1.0.0)
|
26
|
+
dotenv (2.6.0)
|
16
27
|
equalizer (0.0.11)
|
17
28
|
http (3.3.0)
|
18
29
|
addressable (~> 2.3)
|
@@ -23,13 +34,35 @@ GEM
|
|
23
34
|
domain_name (~> 0.5)
|
24
35
|
http-form_data (2.1.1)
|
25
36
|
http_parser.rb (0.6.0)
|
37
|
+
i18n (1.5.1)
|
38
|
+
concurrent-ruby (~> 1.0)
|
26
39
|
memoizable (0.4.2)
|
27
40
|
thread_safe (~> 0.3, >= 0.3.1)
|
41
|
+
method_source (0.9.2)
|
42
|
+
minitest (5.11.3)
|
28
43
|
multipart-post (2.0.0)
|
29
44
|
naught (1.1.0)
|
45
|
+
oj (3.7.6)
|
30
46
|
parallel (1.12.1)
|
47
|
+
pry (0.12.2)
|
48
|
+
coderay (~> 1.1.0)
|
49
|
+
method_source (~> 0.9.0)
|
31
50
|
public_suffix (3.0.3)
|
32
|
-
rake (
|
51
|
+
rake (12.3.2)
|
52
|
+
rb-readline (0.5.5)
|
53
|
+
rspec (3.8.0)
|
54
|
+
rspec-core (~> 3.8.0)
|
55
|
+
rspec-expectations (~> 3.8.0)
|
56
|
+
rspec-mocks (~> 3.8.0)
|
57
|
+
rspec-core (3.8.0)
|
58
|
+
rspec-support (~> 3.8.0)
|
59
|
+
rspec-expectations (3.8.2)
|
60
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
61
|
+
rspec-support (~> 3.8.0)
|
62
|
+
rspec-mocks (3.8.0)
|
63
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
64
|
+
rspec-support (~> 3.8.0)
|
65
|
+
rspec-support (3.8.0)
|
33
66
|
simple_oauth (0.3.1)
|
34
67
|
thread_safe (0.3.6)
|
35
68
|
twitter (6.2.0)
|
@@ -43,6 +76,8 @@ GEM
|
|
43
76
|
multipart-post (~> 2.0)
|
44
77
|
naught (~> 1.0)
|
45
78
|
simple_oauth (~> 0.3.0)
|
79
|
+
tzinfo (1.2.5)
|
80
|
+
thread_safe (~> 0.1)
|
46
81
|
unf (0.1.4)
|
47
82
|
unf_ext
|
48
83
|
unf_ext (0.0.7.5)
|
@@ -51,9 +86,13 @@ PLATFORMS
|
|
51
86
|
ruby
|
52
87
|
|
53
88
|
DEPENDENCIES
|
54
|
-
bundler
|
55
|
-
|
89
|
+
bundler
|
90
|
+
dotenv
|
91
|
+
pry
|
92
|
+
rake
|
93
|
+
rb-readline
|
94
|
+
rspec (~> 3.8)
|
56
95
|
twitter_friendly!
|
57
96
|
|
58
97
|
BUNDLED WITH
|
59
|
-
|
98
|
+
2.0.1
|
data/README.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# twitter_friendly
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/twitter_friendly)
|
4
|
+
[](https://travis-ci.org/ts-3156/twitter_friendly)
|
4
5
|
|
5
|
-
|
6
|
+
A twitter-friendly Ruby interface to the Twitter API. This twitter_friendly gem provides multiple features.
|
7
|
+
|
8
|
+
- Auto pagination
|
9
|
+
- Auto caching
|
10
|
+
- Parallelly fetching
|
6
11
|
|
7
12
|
## Installation
|
8
13
|
|
@@ -14,25 +19,172 @@ gem 'twitter_friendly'
|
|
14
19
|
|
15
20
|
And then execute:
|
16
21
|
|
17
|
-
|
22
|
+
```sh
|
23
|
+
$ bundle
|
24
|
+
```
|
18
25
|
|
19
26
|
Or install it yourself as:
|
20
27
|
|
21
|
-
|
28
|
+
```sh
|
29
|
+
$ gem install twitter_friendly
|
30
|
+
```
|
31
|
+
|
32
|
+
## Configuration
|
33
|
+
|
34
|
+
You can pass configuration options as a block to `TwitterFriendly::Client.new` just like the below.
|
35
|
+
|
36
|
+
```
|
37
|
+
client = TwitterFriendly::Client.new do |config|
|
38
|
+
config.consumer_key = "YOUR_CONSUMER_KEY"
|
39
|
+
config.consumer_secret = "YOUR_CONSUMER_SECRET"
|
40
|
+
config.access_token = "YOUR_ACCESS_TOKEN"
|
41
|
+
config.access_token_secret = "YOUR_ACCESS_SECRET"
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Useful features
|
46
|
+
|
47
|
+
After configuring a `client`, you can do the following things.
|
48
|
+
|
49
|
+
Fetch all friends's user IDs (by screen name or user ID, or by implicit authenticated user)
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
ids = client.follower_ids('gem')
|
53
|
+
ids.size
|
54
|
+
# => 1741
|
55
|
+
```
|
56
|
+
|
57
|
+
As using a cache, it's super fast from the second time.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Benchmark.bm 20 do |r|
|
61
|
+
r.report "Fetch follower_ids" do
|
62
|
+
client.follower_ids('gem')
|
63
|
+
end
|
64
|
+
r.report "(Cached)" do
|
65
|
+
client.follower_ids('gem')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# user system total real
|
70
|
+
# Fetch follower_ids 0.010330 0.003607 0.013937 ( 0.981068)
|
71
|
+
# (Cached) 0.000865 0.000153 0.001018 ( 0.001019) <- Roughly 900 times faster!
|
72
|
+
```
|
73
|
+
|
74
|
+
You don't need to write a boilerplate code as having auto pagination feature.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
users = client.follower_ids('a_user_has_many_friends')
|
78
|
+
users.size
|
79
|
+
# => 50000
|
80
|
+
```
|
81
|
+
|
82
|
+
If you don't use twitter_friendly gem, you must write the code like the below to fetch all follower's ids.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
def collect_with_max_id(collection=[], max_id=nil, &block)
|
86
|
+
response = yield(max_id)
|
87
|
+
collection += response
|
88
|
+
response.empty? ? collection.flatten : collect_with_max_id(collection, response.last.id - 1, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
ids =
|
92
|
+
collect_with_max_id do |max_id|
|
93
|
+
options = {count: 200, include_rts: true}
|
94
|
+
options[:max_id] = max_id unless max_id.nil?
|
95
|
+
client.follower_ids('user_name', options)
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Additionally, twitter_friendly gem has a parallel execution feature.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
ids = [id1, id2, id3, ... , id1000]
|
103
|
+
|
104
|
+
Benchmark.bm 25 do |r|
|
105
|
+
r.report "Fetch users in parallel" do
|
106
|
+
client.users(ids)
|
107
|
+
end
|
108
|
+
|
109
|
+
client.cache.clear
|
22
110
|
|
23
|
-
|
111
|
+
r.report "Fetch users in serial" do
|
112
|
+
client.users(ids, parallel: false)
|
113
|
+
end
|
114
|
+
end
|
24
115
|
|
25
|
-
|
116
|
+
# user system total real
|
117
|
+
# Fetch users in parallel 0.271966 0.057981 0.329947 ( 2.675270) <- Super fast!
|
118
|
+
# Fetch users in serial 0.201375 0.044399 0.245774 ( 8.068372)
|
119
|
+
```
|
120
|
+
|
121
|
+
## Usage examples
|
122
|
+
|
123
|
+
Fetch all friends's user IDs (by screen name or user ID, or by implicit authenticated user)
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
client.friend_ids('gem')
|
127
|
+
client.friend_ids(213747670)
|
128
|
+
client.friend_ids
|
129
|
+
```
|
130
|
+
|
131
|
+
Fetch all followers's user IDs (by screen name or user ID, or by implicit authenticated user)
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
client.follower_ids('gem')
|
135
|
+
client.follower_ids(213747670)
|
136
|
+
client.follower_ids
|
137
|
+
```
|
138
|
+
|
139
|
+
Fetch all friends with profile details (by screen name or user ID, or by implicit authenticated user)
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
client.friends('gem')
|
143
|
+
client.friends(213747670)
|
144
|
+
client.friends
|
145
|
+
```
|
26
146
|
|
27
|
-
|
147
|
+
Fetch all followers with profile details (by screen name or user ID, or by implicit authenticated user)
|
28
148
|
|
29
|
-
|
149
|
+
```ruby
|
150
|
+
client.followers('gem')
|
151
|
+
client.followers(213747670)
|
152
|
+
client.followers
|
153
|
+
```
|
30
154
|
|
31
|
-
|
155
|
+
|
156
|
+
Fetch the timeline of Tweets (by screen name or user ID, or by implicit authenticated user)
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
client.user_timeline('gem')
|
160
|
+
client.user_timeline(213747670)
|
161
|
+
client.user_timeline
|
162
|
+
|
163
|
+
result.size
|
164
|
+
# => 588
|
165
|
+
|
166
|
+
result.first.text
|
167
|
+
# => "Your tweet text..."
|
168
|
+
|
169
|
+
result.first.user.screen_name
|
170
|
+
# => "your_screen_name"
|
171
|
+
```
|
172
|
+
|
173
|
+
Fetch the timeline of Tweets from the authenticated user's home page
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
client.home_timeline
|
177
|
+
```
|
178
|
+
|
179
|
+
Fetch the timeline of Tweets mentioning the authenticated user
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
client.mentions_timeline
|
183
|
+
```
|
32
184
|
|
33
185
|
## Contributing
|
34
186
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
187
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ts-3156/twitter_friendly.
|
36
188
|
|
37
189
|
## License
|
38
190
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dotenv/load'
|
4
|
+
require 'twitter_friendly'
|
5
|
+
|
6
|
+
TwitterFriendly.cache.clear
|
7
|
+
|
8
|
+
client =
|
9
|
+
TwitterFriendly::Client.new(
|
10
|
+
consumer_key: ENV['CK'],
|
11
|
+
consumer_secret: ENV['CS'],
|
12
|
+
access_token: ENV['AT'],
|
13
|
+
access_token_secret: ENV['ATS']
|
14
|
+
)
|
15
|
+
|
16
|
+
def diff(ary1, ary2)
|
17
|
+
[ary1 - ary2, ary2 - ary1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def diff?(ary1, ary2)
|
21
|
+
diff(ary1, ary2).flatten.any?
|
22
|
+
end
|
23
|
+
|
24
|
+
def users_diff(ary1, ary2)
|
25
|
+
diff(ary1.map {|a| a[:id]}, ary2.map {|a| a[:id]})
|
26
|
+
end
|
27
|
+
|
28
|
+
def users_diff?(ary1, ary2)
|
29
|
+
users_diff(ary1, ary2).flatten.any?
|
30
|
+
end
|
31
|
+
|
32
|
+
friend_ids = follower_ids = []
|
33
|
+
|
34
|
+
%i(friend_ids follower_ids).each do |method|
|
35
|
+
ids = client.send(method)
|
36
|
+
cached_ids = client.send(method)
|
37
|
+
raw_ids = client.internal_client.send(method).attrs[:ids]
|
38
|
+
|
39
|
+
puts method
|
40
|
+
puts " fetch #{ids.size}, cache #{cached_ids.size}, raw #{raw_ids.size}"
|
41
|
+
puts " ids is different from cached_ids diff=#{diff(ids, cached_ids).inspect}" if diff?(ids, cached_ids)
|
42
|
+
puts " cached_ids is different from raw_ids diff=#{diff(cached_ids, raw_ids).inspect}" if diff?(cached_ids, raw_ids)
|
43
|
+
puts " ids is different from raw_ids diff=#{diff(ids, raw_ids).inspect}" if diff?(ids, raw_ids)
|
44
|
+
puts " #{client.rate_limit.send(method)}"
|
45
|
+
|
46
|
+
eval("#{method}=ids")
|
47
|
+
end
|
48
|
+
|
49
|
+
client.cache.clear
|
50
|
+
|
51
|
+
ids1, ids2 = client.friend_ids_and_follower_ids
|
52
|
+
cached_ids1, cached_ids2 = client.friend_ids_and_follower_ids
|
53
|
+
|
54
|
+
puts 'friend_ids_and_follower_ids'
|
55
|
+
puts " fetch #{ids1.size}, cache #{cached_ids1.size}"
|
56
|
+
puts " fetch #{ids2.size}, cache #{cached_ids2.size}"
|
57
|
+
puts " ids1 is different from cached_ids1 diff=#{diff(ids1, cached_ids1)}" if diff?(ids1, cached_ids1)
|
58
|
+
puts " ids2 is different from cached_ids2 diff=#{diff(ids2, cached_ids2)}" if diff?(ids2, cached_ids2)
|
59
|
+
|
60
|
+
client.cache.clear
|
61
|
+
|
62
|
+
friends = followers = []
|
63
|
+
|
64
|
+
%i(friends followers).each do |method|
|
65
|
+
users = client.send(method)
|
66
|
+
cached_users = client.send(method)
|
67
|
+
# raw_users = client.internal_client.send(method).attrs[:users]
|
68
|
+
|
69
|
+
puts method
|
70
|
+
puts " users #{users.size}, cached_users #{cached_users.size}"
|
71
|
+
puts " users is different from cached_users diff=#{users_diff(users, cached_users)}" if users_diff?(users, cached_users)
|
72
|
+
# puts " cached_users is different from raw_users" if cached_users != raw_users
|
73
|
+
# puts " users is different from raw_users" if users != raw_users
|
74
|
+
puts " #{client.rate_limit.send(method)}"
|
75
|
+
|
76
|
+
eval("#{method}=users")
|
77
|
+
end
|
78
|
+
|
79
|
+
client.cache.clear
|
80
|
+
|
81
|
+
users1, users2 = client.friends_and_followers
|
82
|
+
cached_users1, cached_users2 = client.friends_and_followers
|
83
|
+
|
84
|
+
puts 'friends_and_followers'
|
85
|
+
puts " fetch #{users1.size}, cache #{cached_users1.size}"
|
86
|
+
puts " fetch #{users2.size}, cache #{cached_users2.size}"
|
87
|
+
puts " users1 is different from cached_users1 diff=#{users_diff(users1, cached_users1)}" if users_diff?(users1, cached_users1)
|
88
|
+
puts " users2 is different from cached_users2 diff=#{users_diff(users2, cached_users2)}" if users_diff?(users2, cached_users2)
|
89
|
+
|
90
|
+
client.cache.clear
|
91
|
+
|
92
|
+
puts friend_ids.zip(friends).all? {|id, user| id == user[:id] }
|
93
|
+
puts follower_ids.zip(followers).all? {|id, user| id == user[:id] }
|
94
|
+
|
95
|
+
puts 'ok'
|