twterm 1.0.12 → 1.1.0.beta1
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/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
|