ex_twitter 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4bd5d8eb5590d0a1eebb86ac2a6d3098c1272467
4
- data.tar.gz: 5c8b5655e88e08dce94069e5850d6c682c7a810a
3
+ metadata.gz: b9fda73eb287f6236f329fc5fb989b8bf5d92a47
4
+ data.tar.gz: 6cb1aba39cd22832b8cc1bdab2ded68dc2fa83a4
5
5
  SHA512:
6
- metadata.gz: 7e7b2026369bc3308a1982d513aff1f2fda23005054220a6bb0fbb791b903a367bc6a2fa0366e5026b12ef6f5e06e7d12ff6c64338e084d39f8625eb2c80b945
7
- data.tar.gz: f7c0d73420daa1ae4d7121f982f1bbf3e6aca81d799bd8ed703504fc94a3a5009a4e47544082a39126af9a20814c7dba9e2823c4577985ddec94afd4db4ae91e
6
+ metadata.gz: dc8aef3495f721143296c30b661562eb5edf45a04e0c9d116809213ef1808626f19aa1c6c57e720422a11bd0af74c8bb4796551fb520509a16acf6a7c96c4ec1
7
+ data.tar.gz: 0be798a390977de38e5cea7cc525c53d8971b8c7f1f498ec86642f72f7dbe4b0a0907e37b44236123381fcc4c4eac4803a07e4ed9ffabbe871e323d108d7011a
data/README.md CHANGED
@@ -1,7 +1,10 @@
1
1
  ex-twitter
2
2
  ==========
3
3
 
4
- A Ruby wrapper to the Twitter gem.
4
+ [![Gem Version](https://badge.fury.io/rb/ex_twitter.png)](https://badge.fury.io/rb/ex_twitter)
5
+ [![Build Status](https://travis-ci.org/ts-3156/ex-twitter.svg?branch=master)](https://travis-ci.org/ts-3156/ex-twitter)
6
+
7
+ Add auto paginate feature to Twitter gem.
5
8
 
6
9
  ## Installation
7
10
 
@@ -17,23 +20,34 @@ Add ex_twitter to your Gemfile, and bundle.
17
20
 
18
21
  ## Features
19
22
 
20
- This gem is a thin wrapper of Twitter gem.
21
- Twitter gem has twitter API like methods.
22
- This gem has high functionality methods and don't raise exceptions.
23
+ * Auto paginate feature
24
+
25
+ ## Configuration
23
26
 
24
- ## Examples
27
+ You can pass configuration options as a block to `ExTwitter.new` just like `Twitter::REST::Client.new`.
25
28
 
26
29
  ```
27
- require 'ex_twitter'
28
- client = ExTwitter.new(config)
30
+ client = ExTwitter.new do |config|
31
+ config.consumer_key = "YOUR_CONSUMER_KEY"
32
+ config.consumer_secret = "YOUR_CONSUMER_SECRET"
33
+ config.access_token = "YOUR_ACCESS_TOKEN"
34
+ config.access_token_secret = "YOUR_ACCESS_SECRET"
35
+ end
36
+ ```
29
37
 
30
- # get all tweets
31
- client.get_all_tweets
38
+ You can pass advanced configuration options as a block to `ExTwitter.new`.
32
39
 
33
- # get all friend ids
34
- client.get_all_friends_ids
40
+ ```
41
+ client = ExTwitter.new do |config|
42
+ config.auto_paginate = true
43
+ config.max_retries = 1
44
+ config.max_paginates = 3
45
+ end
46
+ ```
47
+
48
+ ## Usage Examples
35
49
 
36
- # get all friends in parallel
37
- client.get_users(friend_ids)
50
+ ```
51
+ client.user_timeline
38
52
  ```
39
53
 
data/Rakefile CHANGED
@@ -6,4 +6,4 @@ RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task :test => :spec
8
8
 
9
-
9
+ task default: [:spec]
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.add_development_dependency 'bundler'
10
10
 
11
11
  spec.authors = ['Shinohara Teruki']
12
- spec.description = %q(A wrapper to the Twitter gem.)
12
+ spec.description = %q(Add auto paginate feature to Twitter gem.)
13
13
  spec.email = %w[ts_3156@yahoo.co.jp]
14
14
  spec.files = %w[LICENSE.md README.md Rakefile ex_twitter.gemspec]
15
15
  spec.files += Dir.glob('lib/**/*.rb')
@@ -20,5 +20,5 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = %w[lib]
21
21
  spec.summary = spec.description
22
22
  spec.test_files = Dir.glob('spec/**/*')
23
- spec.version = '0.0.2'
23
+ spec.version = '0.0.3'
24
24
  end
@@ -1,3 +1,5 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext'
1
3
  require 'twitter'
2
4
  require 'yaml'
3
5
  require 'active_support'
@@ -6,58 +8,44 @@ require 'logger'
6
8
 
7
9
  # extended twitter
8
10
  class ExTwitter < Twitter::REST::Client
9
- attr_accessor :cache, :cache_expires_in, :max_attempts, :wait, :auto_paginate, :logger
11
+ attr_accessor :cache, :cache_expires_in, :max_retries, :wait, :auto_paginate, :max_paginates, :logger
10
12
 
11
- MAX_ATTEMPTS = 1
13
+ MAX_RETRIES = 1
12
14
  WAIT = false
13
- CACHE_EXPIRES_IN = 300
14
-
15
- def self.get_config_value(config)
16
- return {} if config.nil?
17
- {
18
- consumer_key: config['consumer_key'],
19
- consumer_secret: config['consumer_secret'],
20
- access_token: config['access_token'],
21
- access_token_secret: config['access_token_secret']
22
- }
23
- end
24
-
25
- def initialize(config={})
26
- if config.empty?
27
- yml_config = if File.exists?(File.expand_path('./', 'config.yml'))
28
- YAML.load_file('config.yml')
29
- elsif File.exists?(File.expand_path('./config/', 'config.yml'))
30
- YAML.load_file('config/config.yml')
31
- end
32
- config = self.class.get_config_value(yml_config)
33
- end
34
-
35
- self.auto_paginate = (config[:auto_paginate] || true)
36
- self.max_attempts = (config[:max_attempts] || MAX_ATTEMPTS)
37
- self.wait = (config[:wait] || WAIT)
38
- self.cache_expires_in = (config[:cache_expires_in] || CACHE_EXPIRES_IN)
39
- self.cache = ActiveSupport::Cache::FileStore.new(File.join(Dir::pwd, 'ex_twitter_cache'),
40
- {expires_in: self.cache_expires_in, race_condition_ttl: self.cache_expires_in})
15
+ # CACHE_EXPIRES_IN = 300
16
+ AUTO_PAGINATE = true
17
+ MAX_PAGINATES = 3
41
18
 
19
+ def initialize(options = {})
42
20
  self.logger = Logger.new(STDOUT)
43
21
  self.logger.level = Logger::DEBUG
44
- super
45
- end
46
22
 
47
- def read(key)
48
- self.cache.read(key)
49
- rescue => e
50
- logger.warn "in read #{key} #{e.inspect}"
51
- nil
52
- end
23
+ self.auto_paginate = AUTO_PAGINATE
24
+ self.max_retries = MAX_RETRIES
25
+ self.wait = WAIT
26
+ self.max_paginates = MAX_PAGINATES
27
+
28
+ # self.cache_expires_in = (config[:cache_expires_in] || CACHE_EXPIRES_IN)
29
+ # self.cache = ActiveSupport::Cache::FileStore.new(File.join(Dir::pwd, 'ex_twitter_cache'),
30
+ # {expires_in: self.cache_expires_in, race_condition_ttl: self.cache_expires_in})
53
31
 
54
- def write(key, value)
55
- self.cache.write(key, value)
56
- rescue => e
57
- logger.warn "in write #{key} #{value} #{e.inspect}"
58
- false
32
+ super
59
33
  end
60
34
 
35
+ # def read(key)
36
+ # self.cache.read(key)
37
+ # rescue => e
38
+ # logger.warn "in read #{key} #{e.inspect}"
39
+ # nil
40
+ # end
41
+ #
42
+ # def write(key, value)
43
+ # self.cache.write(key, value)
44
+ # rescue => e
45
+ # logger.warn "in write #{key} #{value} #{e.inspect}"
46
+ # false
47
+ # end
48
+
61
49
  # githubでは、レスポンスが次のエンドポイントを知っているため、ブロックをデータの結合のみに使っている。引数ではAPI名を渡している。
62
50
  # 一方、twitterでは、レスポンスが次のエンドポイントを知らないため、ブロック内にAPI名を持ち、再帰的にブロックを呼び出している。
63
51
  # また、再帰を使うため、引数をコレクションの引き渡しに使ってしまっている。(この問題については通常のループを使えば解決する)
@@ -72,15 +60,18 @@ class ExTwitter < Twitter::REST::Client
72
60
  #
73
61
  # twitterで再帰方式がとられている理由は、おそらく、一般ユーザー向けのサンプルでメソッド名を渡すようなリフレクションを避けるため、
74
62
  # なのかもしれない。
63
+
64
+ # max_idを使って自動ページングを行う
75
65
  def collect_with_max_id(method_name, *args, &block)
76
- options = args.last.is_a?(Hash) ? args.pop : {}
77
- max_calls = options.delete(:max_calls) || 3
78
- data = last_response = send(method_name, *args, options)
66
+ options = args.extract_options!
79
67
  logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
80
68
 
69
+ max_paginates = options.delete(:max_paginates) || MAX_PAGINATES
70
+ data = last_response = send(method_name, *args, options)
71
+
81
72
  if auto_paginate
82
- num_attempts = 0
83
- (max_calls - 1).times do
73
+ num_retries = 0
74
+ (max_paginates - 1).times do
84
75
  break unless last_response.any?
85
76
 
86
77
  options[:max_id] = last_response.last.id - 1
@@ -89,24 +80,24 @@ class ExTwitter < Twitter::REST::Client
89
80
  last_response = send(method_name, *args, options)
90
81
  logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
91
82
  rescue Twitter::Error::TooManyRequests => e
92
- if num_attempts <= MAX_ATTEMPTS
83
+ if num_retries <= MAX_RETRIES
93
84
  if WAIT
94
85
  sleep e.rate_limit.reset_in
95
- num_attempts += 1
86
+ num_retries += 1
96
87
  retry
97
88
  else
98
89
  logger.warn "retry #{e.rate_limit.reset_in} seconds later, #{e.inspect}"
99
90
  end
100
91
  else
101
- logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
92
+ logger.warn "fail. num_retries > MAX_RETRIES(=#{MAX_RETRIES}), #{e.inspect}"
102
93
  end
103
94
  rescue => e
104
- if num_attempts <= MAX_ATTEMPTS
105
- logger.warn "retry till num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
106
- num_attempts += 1
95
+ if num_retries <= MAX_RETRIES
96
+ logger.warn "retry till num_retries > MAX_RETRIES(=#{MAX_RETRIES}), #{e.inspect}"
97
+ num_retries += 1
107
98
  retry
108
99
  else
109
- logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
100
+ logger.warn "fail. num_retries > MAX_RETRIES(=#{MAX_RETRIES}), something error #{e.inspect}"
110
101
  end
111
102
  end
112
103
 
@@ -121,16 +112,18 @@ class ExTwitter < Twitter::REST::Client
121
112
  data
122
113
  end
123
114
 
115
+ # cursorを使って自動ページングを行う
124
116
  def collect_with_cursor(method_name, *args, &block)
125
- options = args.last.is_a?(Hash) ? args.pop : {}
126
- max_calls = options.delete(:max_calls) || 3
127
- last_response = send(method_name, *args, options).attrs
117
+ options = args.extract_options!
128
118
  logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
119
+
120
+ max_paginates = options.delete(:max_paginates) || MAX_PAGINATES
121
+ last_response = send(method_name, *args, options).attrs
129
122
  data = last_response[:users] || last_response[:ids]
130
123
 
131
124
  if auto_paginate
132
- num_attempts = 0
133
- (max_calls - 1).times do
125
+ num_retries = 0
126
+ (max_paginates - 1).times do
134
127
  next_cursor = last_response[:next_cursor]
135
128
  break if !next_cursor || next_cursor == 0
136
129
 
@@ -140,24 +133,24 @@ class ExTwitter < Twitter::REST::Client
140
133
  last_response = send(method_name, *args, options).attrs
141
134
  logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
142
135
  rescue Twitter::Error::TooManyRequests => e
143
- if num_attempts <= MAX_ATTEMPTS
136
+ if num_retries <= MAX_RETRIES
144
137
  if WAIT
145
138
  sleep e.rate_limit.reset_in
146
- num_attempts += 1
139
+ num_retries += 1
147
140
  retry
148
141
  else
149
142
  logger.warn "retry #{e.rate_limit.reset_in} seconds later, #{e.inspect}"
150
143
  end
151
144
  else
152
- logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
145
+ logger.warn "fail. num_retries > MAX_RETRIES(=#{MAX_RETRIES}), #{e.inspect}"
153
146
  end
154
147
  rescue => e
155
- if num_attempts <= MAX_ATTEMPTS
156
- logger.warn "retry till num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
157
- num_attempts += 1
148
+ if num_retries <= MAX_RETRIES
149
+ logger.warn "retry till num_retries > MAX_RETRIES(=#{MAX_RETRIES}), #{e.inspect}"
150
+ num_retries += 1
158
151
  retry
159
152
  else
160
- logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
153
+ logger.warn "fail. num_retries > MAX_RETRIES(=#{MAX_RETRIES}), something error #{e.inspect}"
161
154
  end
162
155
  end
163
156
 
@@ -174,33 +167,38 @@ class ExTwitter < Twitter::REST::Client
174
167
  end
175
168
 
176
169
  alias :old_user_timeline :user_timeline
177
- def user_timeline(user = nil, options = {})
178
- options = options.merge({count: 200, include_rts: true})
179
- collect_with_max_id(:old_user_timeline, user, options)
170
+ def user_timeline(*args)
171
+ options = {count: 200, include_rts: true}.merge(args.extract_options!)
172
+ collect_with_max_id(:old_user_timeline, *args, options)
173
+ end
174
+
175
+ def user_photos(*args)
176
+ tweets = user_timeline(*args)
177
+ tweets.select{|t| t.media? }.map{|t| t.media }.flatten
180
178
  end
181
179
 
182
180
  alias :old_friends :friends
183
- def friends(user = nil, options = {})
184
- options = options.merge({count: 200, include_user_entities: true})
185
- collect_with_cursor(:old_friends, user, options)
181
+ def friends(*args)
182
+ options = {count: 200, include_user_entities: true}.merge(args.extract_options!)
183
+ collect_with_cursor(:old_friends, *args, options)
186
184
  end
187
185
 
188
186
  alias :old_followers :followers
189
- def followers(user = nil, options = {})
190
- options = options.merge({count: 200, include_user_entities: true})
191
- collect_with_cursor(:old_followers, user, options)
187
+ def followers(*args)
188
+ options = {count: 200, include_user_entities: true}.merge(args.extract_options!)
189
+ collect_with_cursor(:old_followers, *args, options)
192
190
  end
193
191
 
194
192
  alias :old_friend_ids :friend_ids
195
- def friend_ids(user = nil, options = {})
196
- options = options.merge({count: 5000})
197
- collect_with_cursor(:old_friend_ids, user, options)
193
+ def friend_ids(*args)
194
+ options = {count: 5000}.merge(args.extract_options!)
195
+ collect_with_cursor(:old_friend_ids, *args, options)
198
196
  end
199
197
 
200
198
  alias :old_follower_ids :follower_ids
201
- def follower_ids(user = nil, options = {})
202
- options = options.merge({count: 5000})
203
- collect_with_cursor(:old_follower_ids, user, options)
199
+ def follower_ids(*args)
200
+ options = {count: 5000}.merge(args.extract_options!)
201
+ collect_with_cursor(:old_follower_ids, *args, options)
204
202
  end
205
203
 
206
204
  alias :old_users :users
@@ -216,6 +214,10 @@ class ExTwitter < Twitter::REST::Client
216
214
  processed_users.sort_by{|p| p[:i] }.map{|p| p[:users] }.flatten
217
215
  end
218
216
 
217
+
218
+
219
+ # ここから下は実装できているのか不明
220
+
219
221
  # mentions_timeline is to fetch the timeline of Tweets mentioning the authenticated user
220
222
  # get_mentions is to fetch the Tweets mentioning the screen_name's user
221
223
  def get_mentions(screen_name)
@@ -231,13 +233,13 @@ class ExTwitter < Twitter::REST::Client
231
233
  end
232
234
 
233
235
  def search_tweets(str, options)
234
- num_attempts = 0
236
+ num_retries = 0
235
237
  begin
236
- num_attempts += 1
238
+ num_retries += 1
237
239
  result = search(str, options)
238
240
  [result.take(100), nil]
239
241
  rescue Twitter::Error::TooManyRequests => e
240
- if num_attempts <= MAX_ATTEMPTS
242
+ if num_retries <= MAX_RETRIES
241
243
  if WAIT
242
244
  sleep e.rate_limit.reset_in
243
245
  retry
@@ -246,14 +248,14 @@ class ExTwitter < Twitter::REST::Client
246
248
  [[], e]
247
249
  end
248
250
  else
249
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
251
+ puts "fail. num_retries > MAX_RETRIES(=#{MAX_RETRIES})"
250
252
  [[], e]
251
253
  end
252
254
  rescue => e
253
- if num_attempts <= MAX_ATTEMPTS
255
+ if num_retries <= MAX_RETRIES
254
256
  retry
255
257
  else
256
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
258
+ puts "fail. num_retries > MAX_RETRIES(=#{MAX_RETRIES}), something error #{e.inspect}"
257
259
  [[], e]
258
260
  end
259
261
  end
@@ -12,59 +12,79 @@ describe ExTwitter do
12
12
  let(:client) { ExTwitter.new(config) }
13
13
 
14
14
  describe '#initialize' do
15
- end
16
-
17
- describe '#read' do
18
- end
19
-
20
- describe '#write' do
21
- end
22
-
23
- describe '#collect_with_max_id' do
24
- end
15
+ let(:default_value) { 3 }
16
+ let(:value) { 100 }
25
17
 
26
- describe '#collect_with_cursor' do
27
- end
18
+ context 'without params' do
19
+ it "doesn't set max_paginates" do
20
+ expect(ExTwitter.new.max_paginates).to eq(default_value)
21
+ end
22
+ end
28
23
 
29
- describe '#user_timeline' do
30
- it 'call collect_with_max_id' do
31
- expect(client).to receive(:collect_with_max_id)
32
- client.user_timeline
24
+ context 'with params' do
25
+ it 'set max_paginates' do
26
+ expect(ExTwitter.new(max_paginates: value).max_paginates).to eq(value)
27
+ end
33
28
  end
34
- end
35
29
 
36
- describe '#friends' do
37
- it 'call collect_with_cursor' do
38
- expect(client).to receive(:collect_with_cursor)
39
- client.friends
30
+ context 'with block' do
31
+ it 'set max_paginates' do
32
+ expect(ExTwitter.new {|config| config.max_paginates = value }.max_paginates).to eq(value)
33
+ end
40
34
  end
41
35
  end
42
36
 
43
- describe '#followers' do
44
- it 'call collect_with_cursor' do
45
- expect(client).to receive(:collect_with_cursor)
46
- client.followers
47
- end
37
+ describe '#read' do
48
38
  end
49
39
 
50
- describe '#friend_ids' do
51
- it 'call collect_with_cursor' do
52
- expect(client).to receive(:collect_with_cursor)
53
- client.friend_ids
54
- end
40
+ describe '#write' do
55
41
  end
56
42
 
57
- describe '#follower_ids' do
58
- it 'call collect_with_cursor' do
59
- expect(client).to receive(:collect_with_cursor)
60
- client.follower_ids
61
- end
43
+ describe '#collect_with_max_id' do
62
44
  end
63
45
 
64
- describe '#users' do
65
- it 'call old_users' do
66
- expect(client).to receive(:old_users)
67
- client.users([1, 2, 3])
68
- end
46
+ describe '#collect_with_cursor' do
69
47
  end
48
+
49
+ # describe '#user_timeline' do
50
+ # it 'call collect_with_max_id' do
51
+ # expect(client).to receive(:collect_with_max_id)
52
+ # client.user_timeline
53
+ # end
54
+ # end
55
+ #
56
+ # describe '#friends' do
57
+ # it 'call collect_with_cursor' do
58
+ # expect(client).to receive(:collect_with_cursor)
59
+ # client.friends
60
+ # end
61
+ # end
62
+ #
63
+ # describe '#followers' do
64
+ # it 'call collect_with_cursor' do
65
+ # expect(client).to receive(:collect_with_cursor)
66
+ # client.followers
67
+ # end
68
+ # end
69
+ #
70
+ # describe '#friend_ids' do
71
+ # it 'call collect_with_cursor' do
72
+ # expect(client).to receive(:collect_with_cursor)
73
+ # client.friend_ids
74
+ # end
75
+ # end
76
+ #
77
+ # describe '#follower_ids' do
78
+ # it 'call collect_with_cursor' do
79
+ # expect(client).to receive(:collect_with_cursor)
80
+ # client.follower_ids
81
+ # end
82
+ # end
83
+ #
84
+ # describe '#users' do
85
+ # it 'call old_users' do
86
+ # expect(client).to receive(:old_users)
87
+ # client.users([1, 2, 3])
88
+ # end
89
+ # end
70
90
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ex_twitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shinohara Teruki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-16 00:00:00.000000000 Z
11
+ date: 2015-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: twitter
@@ -66,7 +66,7 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description: A wrapper to the Twitter gem.
69
+ description: Add auto paginate feature to Twitter gem.
70
70
  email:
71
71
  - ts_3156@yahoo.co.jp
72
72
  executables: []
@@ -104,7 +104,7 @@ rubyforge_project:
104
104
  rubygems_version: 2.2.2
105
105
  signing_key:
106
106
  specification_version: 4
107
- summary: A wrapper to the Twitter gem.
107
+ summary: Add auto paginate feature to Twitter gem.
108
108
  test_files:
109
109
  - spec/ex_twitter_spec.rb
110
110
  - spec/helper.rb