ex_twitter 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4bd5d8eb5590d0a1eebb86ac2a6d3098c1272467
4
+ data.tar.gz: 5c8b5655e88e08dce94069e5850d6c682c7a810a
5
+ SHA512:
6
+ metadata.gz: 7e7b2026369bc3308a1982d513aff1f2fda23005054220a6bb0fbb791b903a367bc6a2fa0366e5026b12ef6f5e06e7d12ff6c64338e084d39f8625eb2c80b945
7
+ data.tar.gz: f7c0d73420daa1ae4d7121f982f1bbf3e6aca81d799bd8ed703504fc94a3a5009a4e47544082a39126af9a20814c7dba9e2823c4577985ddec94afd4db4ae91e
data/Rakefile CHANGED
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :test => :spec
8
+
9
+
data/ex_twitter.gemspec CHANGED
@@ -5,7 +5,9 @@ Gem::Specification.new do |spec|
5
5
  spec.add_dependency 'twitter'
6
6
  spec.add_dependency 'activesupport'
7
7
  spec.add_dependency 'parallel'
8
+
8
9
  spec.add_development_dependency 'bundler'
10
+
9
11
  spec.authors = ['Shinohara Teruki']
10
12
  spec.description = %q(A wrapper to the Twitter gem.)
11
13
  spec.email = %w[ts_3156@yahoo.co.jp]
@@ -18,5 +20,5 @@ Gem::Specification.new do |spec|
18
20
  spec.require_paths = %w[lib]
19
21
  spec.summary = spec.description
20
22
  spec.test_files = Dir.glob('spec/**/*')
21
- spec.version = '0.0.1'
23
+ spec.version = '0.0.2'
22
24
  end
data/lib/ex_twitter.rb CHANGED
@@ -1,312 +1,219 @@
1
- # -*- coding: utf-8 -*-
2
1
  require 'twitter'
3
2
  require 'yaml'
4
3
  require 'active_support'
5
4
  require 'parallel'
5
+ require 'logger'
6
6
 
7
7
  # extended twitter
8
8
  class ExTwitter < Twitter::REST::Client
9
- attr_accessor :cache, :cache_expires_in
9
+ attr_accessor :cache, :cache_expires_in, :max_attempts, :wait, :auto_paginate, :logger
10
10
 
11
11
  MAX_ATTEMPTS = 1
12
12
  WAIT = false
13
13
  CACHE_EXPIRES_IN = 300
14
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
+
15
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)
16
38
  self.cache_expires_in = (config[:cache_expires_in] || CACHE_EXPIRES_IN)
17
39
  self.cache = ActiveSupport::Cache::FileStore.new(File.join(Dir::pwd, 'ex_twitter_cache'),
18
40
  {expires_in: self.cache_expires_in, race_condition_ttl: self.cache_expires_in})
41
+
42
+ self.logger = Logger.new(STDOUT)
43
+ self.logger.level = Logger::DEBUG
19
44
  super
20
45
  end
21
46
 
22
47
  def read(key)
23
48
  self.cache.read(key)
24
49
  rescue => e
25
- puts "in read #{key} #{e.inspect}"
50
+ logger.warn "in read #{key} #{e.inspect}"
26
51
  nil
27
52
  end
28
53
 
29
54
  def write(key, value)
30
55
  self.cache.write(key, value)
31
56
  rescue => e
32
- puts "in write #{key} #{value} #{e.inspect}"
57
+ logger.warn "in write #{key} #{value} #{e.inspect}"
33
58
  false
34
59
  end
35
60
 
36
- def collect_with_max_id(collection=[], max_id=nil, &block)
37
- response = yield(max_id)
38
- return response unless response[1].nil?
39
-
40
- collection += response[0]
41
- response[0].empty? ? [collection.flatten, nil] : collect_with_max_id(collection, response[0].last.id - 1, &block)
42
- end
43
-
44
- def collect_with_cursor(collection=[], cursor=-1, &block)
45
- response = yield(cursor)
46
- return response unless response[1].nil?
61
+ # githubでは、レスポンスが次のエンドポイントを知っているため、ブロックをデータの結合のみに使っている。引数ではAPI名を渡している。
62
+ # 一方、twitterでは、レスポンスが次のエンドポイントを知らないため、ブロック内にAPI名を持ち、再帰的にブロックを呼び出している。
63
+ # また、再帰を使うため、引数をコレクションの引き渡しに使ってしまっている。(この問題については通常のループを使えば解決する)
64
+ #
65
+ # APIは通常繰り返しの呼び出しになるため、API名は常に同じものを保持しておき、ブロックはデータの結合に使った方が無駄がなく自由度が高い。
66
+ # また、再帰ではなく通常のループを使った方が分かりやすい。
67
+ #
68
+ # このgithub方式を実現するためには、メソッド名(例:user_timeline)を渡し、ループさせるか、user_timelineが内部で使っている
69
+ # objects_from_response_with_userをループさせればよい。
70
+ #
71
+ # この2種類の方法を比較した場合、より外側のレイヤーを使った方が、使うライブラリの内部情報に依存しなくなるため、好ましい。
72
+ #
73
+ # twitterで再帰方式がとられている理由は、おそらく、一般ユーザー向けのサンプルでメソッド名を渡すようなリフレクションを避けるため、
74
+ # なのかもしれない。
75
+ 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)
79
+ logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
47
80
 
48
- collection += (response[0][:users] || response[0][:ids])
49
- next_cursor = response[0][:next_cursor]
50
- next_cursor == 0 ? [collection.flatten, nil] : collect_with_cursor(collection, next_cursor, &block)
51
- end
81
+ if auto_paginate
82
+ num_attempts = 0
83
+ (max_calls - 1).times do
84
+ break unless last_response.any?
52
85
 
53
- def get_latest_200_tweets(user=nil)
54
- num_attempts = 0
55
- options = {count: 200, include_rts: true}
56
- begin
57
- num_attempts += 1
58
- [user_timeline(user, options), nil]
59
- rescue Twitter::Error::TooManyRequests => e
60
- if num_attempts <= MAX_ATTEMPTS
61
- if WAIT
62
- sleep e.rate_limit.reset_in
63
- retry
64
- else
65
- puts "retry #{e.rate_limit.reset_in} seconds later"
66
- [[], e]
67
- end
68
- else
69
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
70
- [[], e]
71
- end
72
- rescue => e
73
- if num_attempts <= MAX_ATTEMPTS
74
- retry
75
- else
76
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
77
- [[], e]
78
- end
79
- end
80
- end
86
+ options[:max_id] = last_response.last.id - 1
81
87
 
82
- def get_all_tweets(user=nil)
83
- num_attempts = 0
84
- collect_with_max_id do |max_id|
85
- options = {count: 200, include_rts: true}
86
- options[:max_id] = max_id unless max_id.nil?
87
- begin
88
- num_attempts += 1
89
- [user_timeline(user, options), nil]
90
- rescue Twitter::Error::TooManyRequests => e
91
- if num_attempts <= MAX_ATTEMPTS
92
- if WAIT
93
- sleep e.rate_limit.reset_in
94
- retry
88
+ begin
89
+ last_response = send(method_name, *args, options)
90
+ logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
91
+ rescue Twitter::Error::TooManyRequests => e
92
+ if num_attempts <= MAX_ATTEMPTS
93
+ if WAIT
94
+ sleep e.rate_limit.reset_in
95
+ num_attempts += 1
96
+ retry
97
+ else
98
+ logger.warn "retry #{e.rate_limit.reset_in} seconds later, #{e.inspect}"
99
+ end
95
100
  else
96
- puts "retry #{e.rate_limit.reset_in} seconds later"
97
- [[], e]
101
+ logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
98
102
  end
99
- else
100
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
101
- [[], e]
102
- end
103
- rescue => e
104
- if num_attempts <= MAX_ATTEMPTS
105
- retry
106
- else
107
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
108
- [[], e]
109
- end
110
- end
111
- end
112
- end
113
-
114
- def get_all_friends(user=nil)
115
- num_attempts = 0
116
- collect_with_cursor do |cursor|
117
- options = {count: 200, include_user_entities: true}
118
- options[:cursor] = cursor unless cursor.nil?
119
- cache_key = "#{self.class.name}:#{__callee__}:#{user}:#{options}"
120
-
121
- cache = self.read(cache_key)
122
- next [cache, nil] unless cache.nil?
123
- begin
124
- num_attempts += 1
125
- object = friends(user, options)
126
- self.write(cache_key, object.attrs)
127
- [object.attrs, nil]
128
- rescue Twitter::Error::TooManyRequests => e
129
- if num_attempts <= MAX_ATTEMPTS
130
- if WAIT
131
- sleep e.rate_limit.reset_in
103
+ 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
132
107
  retry
133
108
  else
134
- puts "retry #{e.rate_limit.reset_in} seconds later"
135
- [{}, e]
109
+ logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
136
110
  end
137
- else
138
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
139
- [{}, e]
140
111
  end
141
- rescue => e
142
- if num_attempts <= MAX_ATTEMPTS
143
- retry
144
- else
145
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
146
- [{}, e]
147
- end
148
- end
149
- end
150
- end
151
112
 
152
- def get_all_followers(user=nil)
153
- num_attempts = 0
154
- collect_with_cursor do |cursor|
155
- options = {count: 200, include_user_entities: true}
156
- options[:cursor] = cursor unless cursor.nil?
157
- cache_key = "#{self.class.name}:#{__callee__}:#{user}:#{options}"
158
-
159
- cache = self.read(cache_key)
160
- next [cache, nil] unless cache.nil?
161
- begin
162
- num_attempts += 1
163
- object = followers(user, options)
164
- self.write(cache_key, object.attrs)
165
- [object.attrs, nil]
166
- rescue Twitter::Error::TooManyRequests => e
167
- if num_attempts <= MAX_ATTEMPTS
168
- if WAIT
169
- sleep e.rate_limit.reset_in
170
- retry
171
- else
172
- puts "retry #{e.rate_limit.reset_in} seconds later"
173
- [{}, e]
174
- end
175
- else
176
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
177
- [{}, e]
178
- end
179
- rescue => e
180
- if num_attempts <= MAX_ATTEMPTS
181
- retry
113
+ if block_given?
114
+ yield(data, last_response)
182
115
  else
183
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
184
- [{}, e]
116
+ data.concat(last_response) if last_response.is_a?(Array)
185
117
  end
186
118
  end
187
119
  end
188
- end
189
120
 
190
- def get_all_friend_ids(user=nil)
191
- num_attempts = 0
192
- collect_with_cursor do |cursor|
193
- options = {count: 5000}
194
- options[:cursor] = cursor unless cursor.nil?
195
- cache_key = "#{self.class.name}:#{__callee__}:#{user}:#{options}"
196
-
197
- cache = self.read(cache_key)
198
- next [cache, nil] unless cache.nil?
199
- begin
200
- num_attempts += 1
201
- object = friend_ids(user, options)
202
- self.write(cache_key, object.attrs)
203
- [object.attrs, nil]
204
- rescue Twitter::Error::TooManyRequests => e
205
- if num_attempts <= MAX_ATTEMPTS
206
- if WAIT
207
- sleep e.rate_limit.reset_in
208
- retry
209
- else
210
- puts "retry #{e.rate_limit.reset_in} seconds later"
211
- [{}, e]
212
- end
213
- else
214
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
215
- [{}, e]
216
- end
217
- rescue => e
218
- if num_attempts <= MAX_ATTEMPTS
219
- retry
220
- else
221
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
222
- [{}, e]
223
- end
224
- end
225
- end
121
+ data
226
122
  end
227
123
 
228
- def get_all_follower_ids(user=nil)
229
- num_attempts = 0
230
- collect_with_cursor do |cursor|
231
- options = {count: 5000}
232
- options[:cursor] = cursor unless cursor.nil?
233
- cache_key = "#{self.class.name}:#{__callee__}:#{user}:#{options}"
234
-
235
- cache = self.read(cache_key)
236
- next [cache, nil] unless cache.nil?
237
- begin
238
- num_attempts += 1
239
- object = follower_ids(user, options)
240
- self.write(cache_key, object.attrs)
241
- [object.attrs, nil]
242
- rescue Twitter::Error::TooManyRequests => e
243
- if num_attempts <= MAX_ATTEMPTS
244
- if WAIT
245
- sleep e.rate_limit.reset_in
246
- retry
247
- else
248
- puts "retry #{e.rate_limit.reset_in} seconds later"
249
- [{}, e]
250
- end
251
- else
252
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
253
- [{}, e]
254
- end
255
- rescue => e
256
- if num_attempts <= MAX_ATTEMPTS
257
- retry
258
- else
259
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
260
- [{}, e]
261
- end
262
- end
263
- end
264
- end
124
+ 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
128
+ logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
129
+ data = last_response[:users] || last_response[:ids]
265
130
 
266
- def get_users(ids)
267
- ids_per_worker = []
268
- while(ids.size > 0)
269
- ids_per_worker << ids.slice!(0, [100, ids.size].min)
270
- end
131
+ if auto_paginate
132
+ num_attempts = 0
133
+ (max_calls - 1).times do
134
+ next_cursor = last_response[:next_cursor]
135
+ break if !next_cursor || next_cursor == 0
136
+
137
+ options[:cursor] = next_cursor
271
138
 
272
- num_attempts = 0
273
- processed_users = []
274
- Parallel.each_with_index(ids_per_worker, in_threads: ids_per_worker.size) do |ids, i|
275
- cache_key = "#{self.class.name}:#{__callee__}:#{i}:#{ids}"
276
- cache = self.read(cache_key)
277
- if cache.nil?
278
139
  begin
279
- num_attempts += 1
280
- object = {i: i, users: users(ids)}
281
- self.write(cache_key, object)
282
- processed_users << object
140
+ last_response = send(method_name, *args, options).attrs
141
+ logger.info "#{method_name}, #{args.inspect} #{options.inspect}"
283
142
  rescue Twitter::Error::TooManyRequests => e
284
143
  if num_attempts <= MAX_ATTEMPTS
285
144
  if WAIT
286
145
  sleep e.rate_limit.reset_in
146
+ num_attempts += 1
287
147
  retry
288
148
  else
289
- puts "retry #{e.rate_limit.reset_in} seconds later"
290
- {i: i, users: [], e: e}
149
+ logger.warn "retry #{e.rate_limit.reset_in} seconds later, #{e.inspect}"
291
150
  end
292
151
  else
293
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS})"
294
- {i: i, users: [], e: e}
152
+ logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
295
153
  end
296
154
  rescue => e
297
155
  if num_attempts <= MAX_ATTEMPTS
156
+ logger.warn "retry till num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), #{e.inspect}"
157
+ num_attempts += 1
298
158
  retry
299
159
  else
300
- puts "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
301
- {i: i, users: [], e: e}
160
+ logger.warn "fail. num_attempts > MAX_ATTEMPTS(=#{MAX_ATTEMPTS}), something error #{e.inspect}"
302
161
  end
303
162
  end
304
- else
305
- processed_users << cache
163
+
164
+ if block_given?
165
+ yield(data, last_response)
166
+ else
167
+ items = last_response[:users] || last_response[:ids]
168
+ data.concat(items) if items.is_a?(Array)
169
+ end
306
170
  end
307
171
  end
308
- # TODO remove if users have error, or raise
309
- processed_users.sort_by{|p|p[:i]}.map{|p|p[:users]}.flatten
172
+
173
+ data
174
+ end
175
+
176
+ 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)
180
+ end
181
+
182
+ 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)
186
+ end
187
+
188
+ 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)
192
+ end
193
+
194
+ 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)
198
+ end
199
+
200
+ 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)
204
+ end
205
+
206
+ alias :old_users :users
207
+ def users(ids, options = {})
208
+ ids_per_worker = ids.each_slice(100).to_a
209
+ processed_users = []
210
+
211
+ Parallel.each_with_index(ids_per_worker, in_threads: ids_per_worker.size) do |ids, i|
212
+ _users = {i: i, users: old_users(ids, options)}
213
+ processed_users << _users
214
+ end
215
+
216
+ processed_users.sort_by{|p| p[:i] }.map{|p| p[:users] }.flatten
310
217
  end
311
218
 
312
219
  # mentions_timeline is to fetch the timeline of Tweets mentioning the authenticated user
@@ -353,26 +260,4 @@ class ExTwitter < Twitter::REST::Client
353
260
  end
354
261
  end
355
262
 
356
- if __FILE__ == $0
357
- puts '--start--'
358
- yml_config = YAML.load_file('config.yml')
359
- config = {
360
- consumer_key: yml_config['consumer_key'],
361
- consumer_secret: yml_config['consumer_secret'],
362
- access_token: yml_config['access_token'],
363
- access_token_secret: yml_config['access_token_secret']
364
- }
365
- client = ExTwitter.new(config)
366
- #followers, error = client.get_all_followers
367
- #puts "#{followers.size} #{error.inspect}"
368
- tweets, error = client.search_tweets_except_rt('#グラドル自画撮り部')
369
- puts tweets.size
370
- tweets.each do |t|
371
- next if !t.media?
372
- puts t.text
373
- puts t.media[0].attrs
374
- puts '----'
375
- end
376
- end
377
-
378
263
 
@@ -0,0 +1,70 @@
1
+ require 'helper'
2
+
3
+ describe ExTwitter do
4
+ let(:config) {
5
+ {
6
+ consumer_key: 'CK',
7
+ consumer_secret: 'CS',
8
+ access_token: 'AT',
9
+ access_token_secret: 'ATS'
10
+ }
11
+ }
12
+ let(:client) { ExTwitter.new(config) }
13
+
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
25
+
26
+ describe '#collect_with_cursor' do
27
+ end
28
+
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
33
+ end
34
+ end
35
+
36
+ describe '#friends' do
37
+ it 'call collect_with_cursor' do
38
+ expect(client).to receive(:collect_with_cursor)
39
+ client.friends
40
+ end
41
+ end
42
+
43
+ describe '#followers' do
44
+ it 'call collect_with_cursor' do
45
+ expect(client).to receive(:collect_with_cursor)
46
+ client.followers
47
+ end
48
+ end
49
+
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
55
+ end
56
+
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
62
+ end
63
+
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
69
+ end
70
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'ex_twitter'
2
+ require 'rspec'
3
+
4
+ RSpec.configure do |config|
5
+ config.expect_with :rspec do |c|
6
+ c.syntax = :expect
7
+ end
8
+ end
metadata CHANGED
@@ -1,78 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ex_twitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Shinohara Teruki
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-03-16 00:00:00.000000000 Z
11
+ date: 2014-12-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: twitter
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: activesupport
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: parallel
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: bundler
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  description: A wrapper to the Twitter gem.
@@ -86,31 +77,34 @@ files:
86
77
  - README.md
87
78
  - Rakefile
88
79
  - ex_twitter.gemspec
89
- - lib/ex_twitter.rb
90
80
  - lib/ex_stream.rb
81
+ - lib/ex_twitter.rb
82
+ - spec/ex_twitter_spec.rb
83
+ - spec/helper.rb
91
84
  homepage: http://github.com/ts-3156/ex-twitter/
92
85
  licenses:
93
86
  - MIT
87
+ metadata: {}
94
88
  post_install_message:
95
89
  rdoc_options: []
96
90
  require_paths:
97
91
  - lib
98
92
  required_ruby_version: !ruby/object:Gem::Requirement
99
- none: false
100
93
  requirements:
101
- - - ! '>='
94
+ - - ">="
102
95
  - !ruby/object:Gem::Version
103
96
  version: '0'
104
97
  required_rubygems_version: !ruby/object:Gem::Requirement
105
- none: false
106
98
  requirements:
107
- - - ! '>='
99
+ - - ">="
108
100
  - !ruby/object:Gem::Version
109
101
  version: '0'
110
102
  requirements: []
111
103
  rubyforge_project:
112
- rubygems_version: 1.8.24
104
+ rubygems_version: 2.2.2
113
105
  signing_key:
114
- specification_version: 3
106
+ specification_version: 4
115
107
  summary: A wrapper to the Twitter gem.
116
- test_files: []
108
+ test_files:
109
+ - spec/ex_twitter_spec.rb
110
+ - spec/helper.rb