twterm 1.0.12 → 1.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/twterm.rb +15 -8
- data/lib/twterm/app.rb +2 -3
- data/lib/twterm/client.rb +218 -68
- data/lib/twterm/filterable_list.rb +2 -1
- data/lib/twterm/friendship.rb +124 -0
- data/lib/twterm/list.rb +5 -3
- data/lib/twterm/promise.rb +143 -0
- data/lib/twterm/screen.rb +0 -1
- data/lib/twterm/status.rb +15 -14
- data/lib/twterm/tab/base.rb +15 -1
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +7 -19
- data/lib/twterm/tab/new/list.rb +9 -15
- data/lib/twterm/tab/new/search.rb +9 -17
- data/lib/twterm/tab/new/start.rb +90 -29
- data/lib/twterm/tab/new/user.rb +5 -7
- data/lib/twterm/tab/scrollable.rb +36 -4
- data/lib/twterm/tab/statuses/base.rb +240 -0
- data/lib/twterm/tab/statuses/conversation.rb +54 -0
- data/lib/twterm/tab/statuses/favorites.rb +45 -0
- data/lib/twterm/tab/statuses/home.rb +36 -0
- data/lib/twterm/tab/statuses/list_timeline.rb +47 -0
- data/lib/twterm/tab/statuses/mentions.rb +40 -0
- data/lib/twterm/tab/statuses/search.rb +42 -0
- data/lib/twterm/tab/statuses/user_timeline.rb +51 -0
- data/lib/twterm/tab/user_tab.rb +288 -19
- data/lib/twterm/tab/users/base.rb +90 -0
- data/lib/twterm/tab/users/followers.rb +41 -0
- data/lib/twterm/tab/users/friends.rb +41 -0
- data/lib/twterm/tab_manager.rb +13 -5
- data/lib/twterm/user.rb +67 -8
- data/lib/twterm/version.rb +1 -1
- data/spec/twterm/friendship_spec.rb +104 -0
- metadata +18 -11
- data/lib/twterm/tab/conversation_tab.rb +0 -49
- data/lib/twterm/tab/list_tab.rb +0 -44
- data/lib/twterm/tab/mentions_tab.rb +0 -36
- data/lib/twterm/tab/search_tab.rb +0 -40
- data/lib/twterm/tab/statuses_tab.rb +0 -251
- data/lib/twterm/tab/timeline_tab.rb +0 -31
- data/lib/twterm/user_window.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21bc4a036d064d1a1a4755eb3655f187ebca6514
|
4
|
+
data.tar.gz: 03be117b59f4775d71aaad2fef2384f916eb4c92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 096afbe0caffeaa8d861e8119b8f35144c93e5ff116e996c4f93c67e8e06eff3a3b9bddf46575441c3f777b222760a4867f78d48f1832773886d4a48c94a429e
|
7
|
+
data.tar.gz: 29a3516e9f86141dea2b74c4b76ebafcd8f3b68cef94284809d3d17507462a6f60f4c7ba832f3df8bfc6b4129081ecd0eafcde46d26750eae493fda29613a45d
|
data/lib/twterm.rb
CHANGED
@@ -8,6 +8,7 @@ require 'launchy'
|
|
8
8
|
require 'oauth'
|
9
9
|
require 'readline'
|
10
10
|
require 'singleton'
|
11
|
+
require 'set'
|
11
12
|
require 'tweetstream'
|
12
13
|
require 'twitter'
|
13
14
|
require 'twitter-text'
|
@@ -25,6 +26,7 @@ require 'twterm/extensions/integer'
|
|
25
26
|
require 'twterm/extensions/string'
|
26
27
|
require 'twterm/filter_query_window'
|
27
28
|
require 'twterm/filterable_list'
|
29
|
+
require 'twterm/friendship'
|
28
30
|
require 'twterm/history/base'
|
29
31
|
require 'twterm/history/hashtag'
|
30
32
|
require 'twterm/history/screen_name'
|
@@ -33,6 +35,7 @@ require 'twterm/notification/base'
|
|
33
35
|
require 'twterm/notification/message'
|
34
36
|
require 'twterm/notification/error'
|
35
37
|
require 'twterm/notifier'
|
38
|
+
require 'twterm/promise'
|
36
39
|
require 'twterm/screen'
|
37
40
|
require 'twterm/scheduler'
|
38
41
|
require 'twterm/status'
|
@@ -41,25 +44,29 @@ require 'twterm/tab/base'
|
|
41
44
|
require 'twterm/tab/dumpable'
|
42
45
|
require 'twterm/tab/exceptions'
|
43
46
|
require 'twterm/tab/scrollable'
|
44
|
-
require 'twterm/tab/statuses_tab'
|
45
|
-
require 'twterm/tab/conversation_tab'
|
46
47
|
require 'twterm/tab/key_assignments_cheatsheet'
|
47
|
-
require 'twterm/tab/list_tab'
|
48
|
-
require 'twterm/tab/mentions_tab'
|
49
48
|
require 'twterm/tab/new/start'
|
50
49
|
require 'twterm/tab/new/list'
|
51
50
|
require 'twterm/tab/new/search'
|
52
51
|
require 'twterm/tab/new/user'
|
53
|
-
require 'twterm/tab/
|
54
|
-
require 'twterm/tab/
|
52
|
+
require 'twterm/tab/statuses/base'
|
53
|
+
require 'twterm/tab/statuses/conversation'
|
54
|
+
require 'twterm/tab/statuses/favorites'
|
55
|
+
require 'twterm/tab/statuses/home'
|
56
|
+
require 'twterm/tab/statuses/list_timeline'
|
57
|
+
require 'twterm/tab/statuses/mentions'
|
58
|
+
require 'twterm/tab/statuses/search'
|
59
|
+
require 'twterm/tab/statuses/user_timeline'
|
55
60
|
require 'twterm/tab/user_tab'
|
61
|
+
require 'twterm/tab/users/base'
|
62
|
+
require 'twterm/tab/users/followers'
|
63
|
+
require 'twterm/tab/users/friends'
|
56
64
|
require 'twterm/tweetbox'
|
57
65
|
require 'twterm/user'
|
58
|
-
require 'twterm/user_window'
|
59
66
|
require 'twterm/version'
|
60
67
|
|
61
68
|
module Twterm
|
62
69
|
class Conf
|
63
|
-
REQUIRE_VERSION = '1.0.
|
70
|
+
REQUIRE_VERSION = '1.1.0.beta1'
|
64
71
|
end
|
65
72
|
end
|
data/lib/twterm/app.rb
CHANGED
@@ -12,17 +12,16 @@ module Twterm
|
|
12
12
|
Screen.instance
|
13
13
|
FilterQueryWindow.instance
|
14
14
|
|
15
|
-
timeline = Tab::
|
15
|
+
timeline = Tab::Statuses::Home.new(client)
|
16
16
|
TabManager.instance.add_and_show(timeline)
|
17
17
|
|
18
|
-
mentions_tab = Tab::
|
18
|
+
mentions_tab = Tab::Statuses::Mentions.new(client)
|
19
19
|
TabManager.instance.add(mentions_tab)
|
20
20
|
TabManager.instance.recover_tabs
|
21
21
|
|
22
22
|
Screen.instance.refresh
|
23
23
|
|
24
24
|
client.stream
|
25
|
-
UserWindow.instance
|
26
25
|
|
27
26
|
reset_interruption_handler
|
28
27
|
end
|
data/lib/twterm/client.rb
CHANGED
@@ -8,6 +8,16 @@ module Twterm
|
|
8
8
|
|
9
9
|
@@instances = []
|
10
10
|
|
11
|
+
def block(*user_ids)
|
12
|
+
send_request do
|
13
|
+
rest_client.block(*user_ids)
|
14
|
+
end.then do |users|
|
15
|
+
users.each do |user|
|
16
|
+
Friendship.block(self.user_id, user.id)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
11
21
|
def connect_stream
|
12
22
|
stream_client.stop_stream
|
13
23
|
|
@@ -24,14 +34,16 @@ module Twterm
|
|
24
34
|
end
|
25
35
|
|
26
36
|
def destroy_status(status)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
37
|
+
send_request_without_catch do
|
38
|
+
rest_client.destroy_status(status.id)
|
39
|
+
end.catch do |reason|
|
40
|
+
case reason
|
41
|
+
when Twitter::Error::NotFound, Twitter::Error::Forbidden
|
32
42
|
Notifier.instance.show_error 'You cannot destroy that status'
|
43
|
+
else
|
44
|
+
raise reason
|
33
45
|
end
|
34
|
-
end
|
46
|
+
end.catch(&show_error)
|
35
47
|
end
|
36
48
|
|
37
49
|
def favorite(status)
|
@@ -39,27 +51,80 @@ module Twterm
|
|
39
51
|
|
40
52
|
send_request do
|
41
53
|
rest_client.favorite(status.id)
|
54
|
+
end.then do
|
42
55
|
status.favorite!
|
43
|
-
yield status if block_given?
|
44
56
|
end
|
57
|
+
end
|
45
58
|
|
46
|
-
|
59
|
+
def favorites(user_id = nil)
|
60
|
+
user_id ||= self.user_id
|
61
|
+
|
62
|
+
send_request do
|
63
|
+
rest_client.favorites(user_id, count: 200)
|
64
|
+
end.then do |tweets|
|
65
|
+
tweets.map(&CREATE_STATUS_PROC)
|
66
|
+
end
|
47
67
|
end
|
48
68
|
|
49
69
|
def fetch_muted_users
|
50
70
|
send_request do
|
51
71
|
@muted_user_ids = rest_client.muted_ids.to_a
|
52
|
-
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def follow(*user_ids)
|
76
|
+
send_request do
|
77
|
+
rest_client.follow(*user_ids)
|
78
|
+
end.then do |users|
|
79
|
+
users.each do |user|
|
80
|
+
if user.protected?
|
81
|
+
Friendship.following_requested(self.user_id, user.id)
|
82
|
+
else
|
83
|
+
Friendship.follow(self.user_id, user.id)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def followers(user_id = nil)
|
90
|
+
user_id ||= self.user_id
|
91
|
+
|
92
|
+
m = Mutex.new
|
93
|
+
|
94
|
+
send_request do
|
95
|
+
rest_client.follower_ids(user_id).each_slice(100) do |user_ids|
|
96
|
+
m.synchronize do
|
97
|
+
users = rest_client.users(*user_ids).map(& -> u { User.new(u) })
|
98
|
+
users.each do |user|
|
99
|
+
Friendship.follow(user.id, self.user_id)
|
100
|
+
end if user_id == self.user_id
|
101
|
+
yield users
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def friends(user_id = nil)
|
108
|
+
user_id ||= self.user_id
|
109
|
+
|
110
|
+
m = Mutex.new
|
111
|
+
|
112
|
+
send_request do
|
113
|
+
rest_client.friend_ids(user_id).each_slice(100) do |user_ids|
|
114
|
+
m.synchronize do
|
115
|
+
yield rest_client.users(*user_ids).map(& -> u { User.new(u) })
|
116
|
+
end
|
117
|
+
end
|
53
118
|
end
|
54
119
|
end
|
55
120
|
|
56
121
|
def home_timeline
|
57
122
|
send_request do
|
58
|
-
|
59
|
-
|
123
|
+
rest_client.home_timeline(count: 200)
|
124
|
+
end.then do |statuses|
|
125
|
+
statuses
|
60
126
|
.select(&@mute_filter)
|
61
127
|
.map(&CREATE_STATUS_PROC)
|
62
|
-
yield statuses
|
63
128
|
end
|
64
129
|
end
|
65
130
|
|
@@ -83,7 +148,9 @@ module Twterm
|
|
83
148
|
|
84
149
|
def list(list_id)
|
85
150
|
send_request do
|
86
|
-
|
151
|
+
rest_client.list(list_id)
|
152
|
+
end.then do |list|
|
153
|
+
List.new(list)
|
87
154
|
end
|
88
155
|
end
|
89
156
|
|
@@ -91,27 +158,66 @@ module Twterm
|
|
91
158
|
fail ArgumentError,
|
92
159
|
'argument must be an instance of List class' unless list.is_a? List
|
93
160
|
send_request do
|
94
|
-
|
95
|
-
|
161
|
+
rest_client.list_timeline(list.id, count: 200)
|
162
|
+
end.then do |statuses|
|
163
|
+
statuses
|
96
164
|
.select(&@mute_filter)
|
97
165
|
.map(&CREATE_STATUS_PROC)
|
98
|
-
yield statuses
|
99
166
|
end
|
100
167
|
end
|
101
168
|
|
102
169
|
def lists
|
103
170
|
send_request do
|
104
|
-
|
171
|
+
rest_client.lists
|
172
|
+
end.then do |lists|
|
173
|
+
lists.map { |list| List.new(list) }
|
105
174
|
end
|
106
175
|
end
|
107
176
|
|
177
|
+
def lookup_friendships
|
178
|
+
user_ids = User.ids.reject { |id| Friendship.already_looked_up?(id) }
|
179
|
+
send_request_without_catch do
|
180
|
+
user_ids.each_slice(100) do |chunked_user_ids|
|
181
|
+
friendships = rest_client.friendships(*chunked_user_ids)
|
182
|
+
friendships.each do |friendship|
|
183
|
+
id = friendship.id
|
184
|
+
client_id = user_id
|
185
|
+
|
186
|
+
conn = friendship.connections
|
187
|
+
conn.include?('blocking') ? Friendship.block(client_id, id) : Friendship.unblock(client_id, id)
|
188
|
+
conn.include?('following') ? Friendship.follow(client_id, id) : Friendship.unfollow(client_id, id)
|
189
|
+
conn.include?('following_requested') ? Friendship.following_requested(client_id, id) : Friendship.following_not_requested(client_id, id)
|
190
|
+
conn.include?('followed_by') ? Friendship.follow(id, client_id) : Friendship.unfollow(id, client_id)
|
191
|
+
conn.include?('muting') ? Friendship.mute(client_id, id) : Friendship.unmute(client_id, id)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end.catch do |e|
|
195
|
+
case e
|
196
|
+
when Twitter::Error::TooManyRequests
|
197
|
+
# do nothing
|
198
|
+
else
|
199
|
+
raise e
|
200
|
+
end
|
201
|
+
end.catch(&show_error)
|
202
|
+
end
|
203
|
+
|
108
204
|
def mentions
|
109
205
|
send_request do
|
110
|
-
|
111
|
-
|
206
|
+
rest_client.mentions(count: 200)
|
207
|
+
end.then do |statuses|
|
208
|
+
statuses
|
112
209
|
.select(&@mute_filter)
|
113
210
|
.map(&CREATE_STATUS_PROC)
|
114
|
-
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def mute(user_ids)
|
215
|
+
send_request do
|
216
|
+
rest_client.mute(*user_ids)
|
217
|
+
end.then do |users|
|
218
|
+
users.each do |user|
|
219
|
+
Friendship.mute(self.user_id, user.id)
|
220
|
+
end
|
115
221
|
end
|
116
222
|
end
|
117
223
|
|
@@ -149,63 +255,66 @@ module Twterm
|
|
149
255
|
fail ArgumentError,
|
150
256
|
'argument must be an instance of Status class' unless status.is_a? Status
|
151
257
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
when
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
'The status is protected'
|
169
|
-
end
|
170
|
-
else
|
171
|
-
raise e
|
258
|
+
send_request_without_catch do
|
259
|
+
rest_client.retweet!(status.id)
|
260
|
+
end.then do
|
261
|
+
status.retweet!
|
262
|
+
end.catch do |reason|
|
263
|
+
message =
|
264
|
+
case reason
|
265
|
+
when Twitter::Error::AlreadyRetweeted
|
266
|
+
'The status is already retweeted'
|
267
|
+
when Twitter::Error::NotFound
|
268
|
+
'The status is not found'
|
269
|
+
when Twitter::Error::Forbidden
|
270
|
+
if status.user.id == user_id # when the status is mine
|
271
|
+
'You cannot retweet your own status'
|
272
|
+
else # when the status is not mine
|
273
|
+
'The status is protected'
|
172
274
|
end
|
173
|
-
|
174
|
-
|
175
|
-
|
275
|
+
else
|
276
|
+
raise e
|
277
|
+
end
|
278
|
+
Notifier.instance.show_error "Retweet attempt failed: #{message}"
|
279
|
+
end.catch(&show_error)
|
176
280
|
end
|
177
281
|
|
178
282
|
def saved_search
|
179
283
|
send_request do
|
180
|
-
|
284
|
+
rest_client.saved_searches
|
181
285
|
end
|
182
286
|
end
|
183
287
|
|
184
288
|
def search(query)
|
185
289
|
send_request do
|
186
|
-
|
187
|
-
|
290
|
+
rest_client.search(query, count: 200)
|
291
|
+
end.then do |statuses|
|
292
|
+
statuses
|
188
293
|
.select(&@mute_filter)
|
189
294
|
.map(&CREATE_STATUS_PROC)
|
190
|
-
yield statuses
|
191
295
|
end
|
192
296
|
end
|
193
297
|
|
194
298
|
def show_status(status_id)
|
195
299
|
send_request do
|
196
|
-
|
300
|
+
rest_client.status(status_id)
|
301
|
+
end.then do |status|
|
302
|
+
Status.new(status)
|
197
303
|
end
|
198
304
|
end
|
199
305
|
|
200
306
|
def show_user(query)
|
201
|
-
|
202
|
-
user
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
307
|
+
send_request_without_catch do
|
308
|
+
rest_client.user(query)
|
309
|
+
end.catch do |reason|
|
310
|
+
case reason
|
311
|
+
when Twitter::Error::NotFound
|
312
|
+
nil
|
313
|
+
else
|
314
|
+
raise reason
|
315
|
+
end
|
316
|
+
end.catch(&show_error).then do |user|
|
317
|
+
user.nil? ? nil : User.new(user)
|
209
318
|
end
|
210
319
|
end
|
211
320
|
|
@@ -252,24 +361,54 @@ module Twterm
|
|
252
361
|
)
|
253
362
|
end
|
254
363
|
|
364
|
+
def unblock(*user_ids)
|
365
|
+
send_request do
|
366
|
+
rest_client.unblock(*user_ids)
|
367
|
+
end.then do |users|
|
368
|
+
users.each do |user|
|
369
|
+
Friendship.unblock(self.user_id, user.id)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
255
374
|
def unfavorite(status)
|
256
375
|
fail ArgumentError,
|
257
376
|
'argument must be an instance of Status class' unless status.is_a? Status
|
258
377
|
|
259
378
|
send_request do
|
260
379
|
rest_client.unfavorite(status.id)
|
380
|
+
end.then do
|
261
381
|
status.unfavorite!
|
262
|
-
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
def unfollow(*user_ids)
|
386
|
+
send_request do
|
387
|
+
rest_client.unfollow(*user_ids)
|
388
|
+
end.then do |users|
|
389
|
+
users.each do |user|
|
390
|
+
Friendship.unfollow(self.user_id, user.id)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
def unmute(user_ids)
|
396
|
+
send_request do
|
397
|
+
rest_client.unmute(*user_ids)
|
398
|
+
end.then do |users|
|
399
|
+
users.each do |user|
|
400
|
+
Friendship.unmute(self.user_id, user.id)
|
401
|
+
end
|
263
402
|
end
|
264
403
|
end
|
265
404
|
|
266
405
|
def user_timeline(user_id)
|
267
406
|
send_request do
|
268
|
-
|
269
|
-
|
407
|
+
rest_client.user_timeline(user_id, count: 200)
|
408
|
+
end.then do |statuses|
|
409
|
+
statuses
|
270
410
|
.select(&@mute_filter)
|
271
411
|
.map(&CREATE_STATUS_PROC)
|
272
|
-
yield statuses
|
273
412
|
end
|
274
413
|
end
|
275
414
|
|
@@ -285,6 +424,17 @@ module Twterm
|
|
285
424
|
|
286
425
|
private
|
287
426
|
|
427
|
+
def show_error
|
428
|
+
proc do |e|
|
429
|
+
case e
|
430
|
+
when Twitter::Error
|
431
|
+
Notifier.instance.show_error "Failed to send request: #{e.message}"
|
432
|
+
else
|
433
|
+
raise e
|
434
|
+
end
|
435
|
+
end.freeze
|
436
|
+
end
|
437
|
+
|
288
438
|
def invoke_callbacks(event, data = nil)
|
289
439
|
return if @callbacks[event].nil?
|
290
440
|
|
@@ -299,15 +449,15 @@ module Twterm
|
|
299
449
|
end
|
300
450
|
|
301
451
|
def send_request(&block)
|
302
|
-
|
452
|
+
send_request_without_catch(&block).catch(&show_error)
|
453
|
+
end
|
454
|
+
|
455
|
+
def send_request_without_catch(&block)
|
456
|
+
Promise.new do |resolve, reject|
|
303
457
|
begin
|
304
|
-
block.call
|
305
|
-
rescue Twitter::Error =>
|
306
|
-
|
307
|
-
if e.message == 'getaddrinfo: nodename nor servname provided, or not known'
|
308
|
-
sleep 10
|
309
|
-
retry
|
310
|
-
end
|
458
|
+
resolve.(block.call)
|
459
|
+
rescue Twitter::Error => reason
|
460
|
+
reject.(reason)
|
311
461
|
end
|
312
462
|
end
|
313
463
|
end
|