twterm 1.3.0 → 2.0.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/README.md +14 -18
- data/bin/twterm +1 -1
- data/lib/twterm/app.rb +120 -30
- data/lib/twterm/client.rb +10 -13
- data/lib/twterm/completion_mamanger.rb +11 -6
- data/lib/twterm/direct_message.rb +6 -28
- data/lib/twterm/direct_message_composer.rb +10 -5
- data/lib/twterm/direct_message_manager.rb +5 -6
- data/lib/twterm/event/notification/abstract_notification.rb +27 -0
- data/lib/twterm/event/notification/error.rb +13 -0
- data/lib/twterm/event/notification/info.rb +13 -0
- data/lib/twterm/event/notification/success.rb +13 -0
- data/lib/twterm/event/notification/warning.rb +13 -0
- data/lib/twterm/event_dispatcher.rb +1 -1
- data/lib/twterm/extensions/array.rb +5 -0
- data/lib/twterm/extensions/enumerator/lazy.rb +3 -0
- data/lib/twterm/extensions/string.rb +0 -4
- data/lib/twterm/friendship.rb +1 -85
- data/lib/twterm/image/between.rb +31 -0
- data/lib/twterm/image/blank_line.rb +21 -0
- data/lib/twterm/image/bold.rb +31 -0
- data/lib/twterm/image/brackets.rb +21 -0
- data/lib/twterm/image/color.rb +45 -0
- data/lib/twterm/image/empty.rb +21 -0
- data/lib/twterm/image/horizontal_sequential_image.rb +48 -0
- data/lib/twterm/image/parens.rb +21 -0
- data/lib/twterm/image/string_image.rb +38 -0
- data/lib/twterm/image/vertical_sequential_image.rb +43 -0
- data/lib/twterm/image.rb +107 -0
- data/lib/twterm/key_mapper/abstract_key_mapper.rb +51 -0
- data/lib/twterm/key_mapper/app_key_mapper.rb +13 -0
- data/lib/twterm/key_mapper/cursor_key_mapper.rb +13 -0
- data/lib/twterm/key_mapper/general_key_mapper.rb +18 -0
- data/lib/twterm/key_mapper/no_such_command.rb +20 -0
- data/lib/twterm/key_mapper/no_such_key.rb +16 -0
- data/lib/twterm/key_mapper/status_key_mapper.rb +18 -0
- data/lib/twterm/key_mapper/tab_key_mapper.rb +31 -0
- data/lib/twterm/key_mapper.rb +127 -0
- data/lib/twterm/list.rb +0 -31
- data/lib/twterm/notifier.rb +7 -7
- data/lib/twterm/repository/abstract_entity_repository.rb +41 -0
- data/lib/twterm/repository/abstract_expirable_entity_repository.rb +35 -0
- data/lib/twterm/repository/abstract_repository.rb +64 -0
- data/lib/twterm/repository/direct_message_repository.rb +14 -0
- data/lib/twterm/repository/friendship_repository.rb +108 -0
- data/lib/twterm/repository/hashtag_repository.rb +39 -0
- data/lib/twterm/repository/list_repository.rb +14 -0
- data/lib/twterm/repository/status_repository.rb +36 -0
- data/lib/twterm/repository/user_repository.rb +22 -0
- data/lib/twterm/rest_client.rb +107 -63
- data/lib/twterm/screen.rb +21 -15
- data/lib/twterm/search_query_window.rb +139 -0
- data/lib/twterm/status.rb +14 -108
- data/lib/twterm/streaming_client.rb +13 -12
- data/lib/twterm/tab/base.rb +48 -8
- data/lib/twterm/tab/direct_message/conversation.rb +53 -52
- data/lib/twterm/tab/direct_message/conversation_list.rb +46 -45
- data/lib/twterm/tab/dumpable.rb +3 -3
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +58 -57
- data/lib/twterm/tab/loadable.rb +20 -0
- data/lib/twterm/tab/new/list.rb +32 -43
- data/lib/twterm/tab/new/search.rb +31 -44
- data/lib/twterm/tab/new/start.rb +44 -55
- data/lib/twterm/tab/new/user.rb +15 -12
- data/lib/twterm/tab/rate_limit_status.rb +84 -0
- data/lib/twterm/tab/scrollable.rb +39 -19
- data/lib/twterm/tab/searchable.rb +133 -0
- data/lib/twterm/tab/statuses/base.rb +139 -129
- data/lib/twterm/tab/statuses/conversation.rb +26 -15
- data/lib/twterm/tab/statuses/favorites.rb +10 -8
- data/lib/twterm/tab/statuses/home.rb +10 -9
- data/lib/twterm/tab/statuses/list_timeline.rb +12 -8
- data/lib/twterm/tab/statuses/mentions.rb +17 -11
- data/lib/twterm/tab/statuses/search.rb +8 -5
- data/lib/twterm/tab/statuses/user_timeline.rb +11 -8
- data/lib/twterm/tab/user_list_management.rb +109 -0
- data/lib/twterm/tab/user_tab.rb +125 -126
- data/lib/twterm/tab/users/base.rb +39 -41
- data/lib/twterm/tab/users/followers.rb +9 -6
- data/lib/twterm/tab/users/friends.rb +9 -6
- data/lib/twterm/tab_manager.rb +64 -40
- data/lib/twterm/tweetbox.rb +18 -13
- data/lib/twterm/uri_opener.rb +2 -1
- data/lib/twterm/user.rb +2 -110
- data/lib/twterm/version.rb +1 -1
- data/lib/twterm/view.rb +30 -0
- data/lib/twterm.rb +3 -9
- data/spec/fixtures/status.json +107 -0
- data/spec/fixtures/user.json +102 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/supports/shared_examples/abstract_key_mapper.rb +17 -0
- data/spec/twterm/extension/enumerator/lazy_spec.rb +11 -0
- data/spec/twterm/friendship_spec.rb +0 -102
- data/spec/twterm/image/blank_line_spec.rb +11 -0
- data/spec/twterm/image/brackets_spec.rb +12 -0
- data/spec/twterm/image/color_spec.rb +22 -0
- data/spec/twterm/image/empry_spec.rb +11 -0
- data/spec/twterm/image/horizontal_sequential_image_spec.rb +15 -0
- data/spec/twterm/image/parens_spec.rb +12 -0
- data/spec/twterm/image/string_image_spec.rb +12 -0
- data/spec/twterm/image/vertical_sequential_image_spec.rb +14 -0
- data/spec/twterm/image_spec.rb +65 -0
- data/spec/twterm/key_mapper/abstract_key_mapper_spec.rb +21 -0
- data/spec/twterm/key_mapper/app_key_mapper_spec.rb +7 -0
- data/spec/twterm/key_mapper/status_key_mapper_spec.rb +7 -0
- data/spec/twterm/key_mapper/tab_key_mapper_spec.rb +7 -0
- data/spec/twterm/repository/friendship_repository_spec.rb +108 -0
- data/spec/twterm/status_spec.rb +58 -0
- data/spec/twterm/user_spec.rb +94 -0
- data/twterm.gemspec +13 -10
- metadata +129 -35
- data/lib/twterm/event/notification.rb +0 -33
- data/lib/twterm/extensions/integer.rb +0 -5
- data/lib/twterm/filter_query_window.rb +0 -91
- data/lib/twterm/filterable_list.rb +0 -41
- data/lib/twterm/history/base.rb +0 -21
- data/lib/twterm/history/hashtag.rb +0 -13
- data/lib/twterm/history/savable.rb +0 -37
- data/lib/twterm/history/screen_name.rb +0 -11
- data/lib/twterm/promise.rb +0 -143
@@ -13,18 +13,21 @@ module Twterm
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def fetch
|
16
|
-
|
16
|
+
client.friends(user_id) do |users|
|
17
17
|
@user_ids.concat(users.map(&:id)).uniq!
|
18
|
-
|
18
|
+
render
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def initialize(user_id)
|
23
|
-
super()
|
22
|
+
def initialize(app, client, user_id)
|
23
|
+
super(app, client)
|
24
24
|
|
25
25
|
@user_id = user_id
|
26
26
|
|
27
|
-
fetch
|
27
|
+
fetch.then do
|
28
|
+
initially_loaded!
|
29
|
+
move_to_top
|
30
|
+
end
|
28
31
|
end
|
29
32
|
|
30
33
|
def title
|
@@ -34,7 +37,7 @@ module Twterm
|
|
34
37
|
private
|
35
38
|
|
36
39
|
def user
|
37
|
-
|
40
|
+
app.user_repository.find(user_id)
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|
data/lib/twterm/tab_manager.rb
CHANGED
@@ -2,10 +2,10 @@ require 'twterm/event/screen/resize'
|
|
2
2
|
require 'twterm/publisher'
|
3
3
|
require 'twterm/subscriber'
|
4
4
|
require 'twterm/utils'
|
5
|
+
require 'twterm/view'
|
5
6
|
|
6
7
|
module Twterm
|
7
8
|
class TabManager
|
8
|
-
include Singleton
|
9
9
|
include Curses
|
10
10
|
include Publisher
|
11
11
|
include Subscriber
|
@@ -31,7 +31,7 @@ module Twterm
|
|
31
31
|
def add_and_show(tab)
|
32
32
|
result = add(tab)
|
33
33
|
@index = @tabs.count - 1 if result
|
34
|
-
current_tab.
|
34
|
+
current_tab.render
|
35
35
|
refresh_window
|
36
36
|
result
|
37
37
|
end
|
@@ -42,10 +42,10 @@ module Twterm
|
|
42
42
|
@history.delete_if { |n| n == @index }
|
43
43
|
@history = @history.map { |i| i > @index ? i - 1 : i }
|
44
44
|
@index = @history.first
|
45
|
-
current_tab.
|
45
|
+
current_tab.render
|
46
46
|
refresh_window
|
47
47
|
rescue Tab::NotClosableError
|
48
|
-
publish(Event::Notification.new(
|
48
|
+
publish(Event::Notification::Warning.new('this tab cannot be closed'))
|
49
49
|
end
|
50
50
|
|
51
51
|
def current_tab
|
@@ -69,7 +69,9 @@ module Twterm
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
def initialize
|
72
|
+
def initialize(app, client)
|
73
|
+
@app, @client = app, client
|
74
|
+
|
73
75
|
@tabs = []
|
74
76
|
@index = 0
|
75
77
|
@history = []
|
@@ -80,71 +82,83 @@ module Twterm
|
|
80
82
|
end
|
81
83
|
|
82
84
|
def open_my_profile
|
83
|
-
current_user_id =
|
84
|
-
tab = Tab::UserTab.new(current_user_id)
|
85
|
+
current_user_id = client.user_id
|
86
|
+
tab = Tab::UserTab.new(app, client, current_user_id)
|
85
87
|
add_and_show(tab)
|
86
88
|
end
|
87
89
|
|
88
90
|
def open_new
|
89
|
-
tab = Tab::New::Start.new
|
91
|
+
tab = Tab::New::Start.new(app, client)
|
90
92
|
add_and_show(tab)
|
91
93
|
end
|
92
94
|
|
93
95
|
def recover_tabs
|
94
96
|
unless File.exist? DUMPED_TABS_FILE
|
95
|
-
tab = Tab::KeyAssignmentsCheatsheet.new
|
97
|
+
tab = Tab::KeyAssignmentsCheatsheet.new(app, client)
|
96
98
|
add(tab)
|
97
99
|
return
|
98
100
|
end
|
99
101
|
|
100
102
|
data = YAML.load(File.read(DUMPED_TABS_FILE))
|
101
103
|
data.each do |klass, title, arg|
|
102
|
-
tab = klass.recover(title, arg)
|
104
|
+
tab = klass.recover(app, client, title, arg)
|
103
105
|
add(tab)
|
104
106
|
end
|
105
107
|
rescue
|
106
|
-
publish(Event::Notification.new(
|
108
|
+
publish(Event::Notification::Error.new('Failed to recover tabs'))
|
107
109
|
end
|
108
110
|
|
109
111
|
def refresh_window
|
110
112
|
@window.clear
|
111
|
-
|
113
|
+
view.render
|
114
|
+
@window.refresh
|
115
|
+
end
|
112
116
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
if tab.object_id == current_tab_id
|
117
|
-
@window.bold do
|
118
|
-
@window.addstr(tab.title)
|
119
|
-
end
|
120
|
-
else
|
121
|
-
@window.addstr(tab.title)
|
122
|
-
end
|
123
|
-
@window.addstr(' | ')
|
124
|
-
end
|
117
|
+
def view
|
118
|
+
wss = Image.string(' ')
|
119
|
+
pipe = Image.string('|')
|
125
120
|
|
126
|
-
@
|
121
|
+
image = @tabs
|
122
|
+
.map { |t| [t, Image.string(t.title)] }
|
123
|
+
.map { |t, r| t.equal?(current_tab) ? !r : r }
|
124
|
+
.reduce(pipe) { |acc, x| acc - wss - x - wss - pipe }
|
125
|
+
|
126
|
+
View.new(@window, image).at(1, 1)
|
127
127
|
end
|
128
128
|
|
129
129
|
def respond_to_key(key)
|
130
|
+
k = KeyMapper.instance
|
131
|
+
|
130
132
|
case key
|
131
|
-
when
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
when
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
when
|
133
|
+
when k[:tab, :'1st']
|
134
|
+
show_nth_tab(0)
|
135
|
+
when k[:tab, :'2nd']
|
136
|
+
show_nth_tab(1)
|
137
|
+
when k[:tab, :'3rd']
|
138
|
+
show_nth_tab(2)
|
139
|
+
when k[:tab, :'4th']
|
140
|
+
show_nth_tab(3)
|
141
|
+
when k[:tab, :'5th']
|
142
|
+
show_nth_tab(4)
|
143
|
+
when k[:tab, :'6th']
|
144
|
+
show_nth_tab(5)
|
145
|
+
when k[:tab, :'7th']
|
146
|
+
show_nth_tab(6)
|
147
|
+
when k[:tab, :'8th']
|
148
|
+
show_nth_tab(7)
|
149
|
+
when k[:tab, :'9th']
|
150
|
+
show_nth_tab(8)
|
151
|
+
when k[:tab, :last]
|
152
|
+
show_nth_tab(@tabs.count - 1)
|
153
|
+
when k[:general, :left], Curses::Key::LEFT
|
140
154
|
show_previous
|
141
|
-
when
|
155
|
+
when k[:general, :right], Curses::Key::RIGHT
|
142
156
|
show_next
|
143
|
-
when
|
157
|
+
when k[:app, :me]
|
144
158
|
open_my_profile
|
145
|
-
when
|
159
|
+
when k[:tab, :new]
|
146
160
|
open_new
|
147
|
-
when
|
161
|
+
when k[:tab, :close]
|
148
162
|
close
|
149
163
|
else
|
150
164
|
return false
|
@@ -154,13 +168,21 @@ module Twterm
|
|
154
168
|
|
155
169
|
def show_next
|
156
170
|
@index = (@index + 1) % @tabs.count
|
157
|
-
current_tab.
|
171
|
+
current_tab.render
|
172
|
+
refresh_window
|
173
|
+
end
|
174
|
+
|
175
|
+
def show_nth_tab(n)
|
176
|
+
return unless n < @tabs.count
|
177
|
+
|
178
|
+
@index = n
|
179
|
+
current_tab.render
|
158
180
|
refresh_window
|
159
181
|
end
|
160
182
|
|
161
183
|
def show_previous
|
162
184
|
@index = (@index - 1) % @tabs.count
|
163
|
-
current_tab.
|
185
|
+
current_tab.render
|
164
186
|
refresh_window
|
165
187
|
end
|
166
188
|
|
@@ -171,6 +193,8 @@ module Twterm
|
|
171
193
|
|
172
194
|
private
|
173
195
|
|
196
|
+
attr_reader :app, :client
|
197
|
+
|
174
198
|
def resize(event)
|
175
199
|
@window.resize(3, stdscr.maxx)
|
176
200
|
@window.move(0, 0)
|
data/lib/twterm/tweetbox.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'twterm/publisher'
|
2
|
+
require 'twterm/event/notification/error'
|
2
3
|
|
3
4
|
module Twterm
|
4
5
|
class Tweetbox
|
@@ -6,24 +7,28 @@ module Twterm
|
|
6
7
|
class InvalidCharactersError < StandardError; end
|
7
8
|
class TextTooLongError < StandardError; end
|
8
9
|
|
9
|
-
include Singleton
|
10
10
|
include Readline
|
11
11
|
include Curses
|
12
12
|
include Publisher
|
13
13
|
|
14
|
+
def initialize(app, client)
|
15
|
+
@app, @client = app, client
|
16
|
+
end
|
17
|
+
|
14
18
|
def compose(in_reply_to = nil)
|
15
19
|
@text = ''
|
16
20
|
|
17
|
-
|
18
|
-
|
21
|
+
@in_reply_to, screen_name =
|
22
|
+
if in_reply_to.is_a?(Status)
|
23
|
+
[in_reply_to, app.user_repository.find(in_reply_to.user_id).screen_name]
|
19
24
|
else
|
20
|
-
|
25
|
+
[nil, nil]
|
21
26
|
end
|
22
27
|
|
23
28
|
resetter = proc do
|
24
29
|
reset_prog_mode
|
25
30
|
sleep 0.1
|
26
|
-
|
31
|
+
app.screen.refresh
|
27
32
|
end
|
28
33
|
|
29
34
|
thread = Thread.new do
|
@@ -32,14 +37,14 @@ module Twterm
|
|
32
37
|
if in_reply_to.nil?
|
33
38
|
puts "\nCompose new tweet:"
|
34
39
|
else
|
35
|
-
puts "\nReply to @#{
|
40
|
+
puts "\nReply to @#{screen_name}'s tweet: \"#{in_reply_to.text}\""
|
36
41
|
end
|
37
42
|
|
38
|
-
|
43
|
+
app.completion_manager.set_default_mode!
|
39
44
|
|
40
45
|
loop do
|
41
46
|
loop do
|
42
|
-
msg = in_reply_to.nil? || !text.empty? ? '> ' : "> @#{
|
47
|
+
msg = in_reply_to.nil? || !text.empty? ? '> ' : "> @#{screen_name} "
|
43
48
|
line = (readline(msg, true) || '').strip
|
44
49
|
break if line.empty?
|
45
50
|
|
@@ -72,7 +77,7 @@ module Twterm
|
|
72
77
|
post
|
73
78
|
end
|
74
79
|
|
75
|
-
|
80
|
+
app.register_interruption_handler do
|
76
81
|
thread.kill
|
77
82
|
clear
|
78
83
|
puts "\nCanceled"
|
@@ -84,7 +89,7 @@ module Twterm
|
|
84
89
|
|
85
90
|
private
|
86
91
|
|
87
|
-
attr_reader :in_reply_to
|
92
|
+
attr_reader :app, :client, :in_reply_to
|
88
93
|
|
89
94
|
def clear
|
90
95
|
@text = ''
|
@@ -93,13 +98,13 @@ module Twterm
|
|
93
98
|
|
94
99
|
def post
|
95
100
|
validate_text!
|
96
|
-
|
101
|
+
client.post(text, in_reply_to)
|
97
102
|
rescue EmptyTextError
|
98
103
|
# do nothing
|
99
104
|
rescue InvalidCharactersError
|
100
|
-
publish(Event::Notification.new(
|
105
|
+
publish(Event::Notification::Error.new('Text contains invalid characters'))
|
101
106
|
rescue TextTooLongError
|
102
|
-
publish(Event::Notification.new(
|
107
|
+
publish(Event::Notification::Error.new("Text is too long (#{text_length} / 140 characters)"))
|
103
108
|
ensure
|
104
109
|
clear
|
105
110
|
end
|
data/lib/twterm/uri_opener.rb
CHANGED
@@ -3,6 +3,7 @@ require 'singleton'
|
|
3
3
|
require 'twterm/event/open_uri'
|
4
4
|
require 'twterm/publisher'
|
5
5
|
require 'twterm/subscriber'
|
6
|
+
require 'twterm/event/notification/warning'
|
6
7
|
|
7
8
|
module Twterm
|
8
9
|
class URIOpener
|
@@ -19,7 +20,7 @@ module Twterm
|
|
19
20
|
def open(uri)
|
20
21
|
Launchy.open(uri)
|
21
22
|
rescue Launchy::CommandNotFoundError
|
22
|
-
publish(Event::Notification.new(
|
23
|
+
publish(Event::Notification::Warning.new('Browser not found'))
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
data/lib/twterm/user.rb
CHANGED
@@ -2,70 +2,22 @@ module Twterm
|
|
2
2
|
class User
|
3
3
|
attr_reader :color, :description, :favorites_count, :followers_count,
|
4
4
|
:friends_count, :id, :location, :name, :protected,
|
5
|
-
:screen_name, :statuses_count, :
|
5
|
+
:screen_name, :statuses_count, :verified, :website
|
6
6
|
alias_method :protected?, :protected
|
7
7
|
alias_method :verified?, :verified
|
8
8
|
|
9
|
-
MAX_CACHED_TIME = 3600
|
10
9
|
COLORS = [:red, :blue, :green, :cyan, :yellow, :magenta]
|
11
10
|
|
12
|
-
@@instances = {}
|
13
|
-
|
14
|
-
def blocked_by?(user_id)
|
15
|
-
Friendship.blocking?(user_id, id)
|
16
|
-
end
|
17
|
-
|
18
|
-
def blocking?(user_id)
|
19
|
-
Friendship.blocking?(id, user_id)
|
20
|
-
end
|
21
|
-
|
22
|
-
def followed_by?(user_id)
|
23
|
-
Friendship.following?(user_id, id)
|
24
|
-
end
|
25
|
-
|
26
|
-
def following?(user_id)
|
27
|
-
Friendship.following?(id, user_id)
|
28
|
-
end
|
29
|
-
|
30
|
-
def following_requested?(user_id)
|
31
|
-
Friendship.following_requested?(id, user_id)
|
32
|
-
end
|
33
|
-
|
34
|
-
def following_requested_by?(user_id)
|
35
|
-
Friendship.following_requested?(user_id, id)
|
36
|
-
end
|
37
|
-
|
38
11
|
def initialize(user)
|
39
12
|
@id = user.id
|
40
13
|
update!(user)
|
41
14
|
@color = COLORS[@id % 6]
|
42
|
-
touch!
|
43
|
-
|
44
|
-
@@instances[@id] = self
|
45
|
-
end
|
46
|
-
|
47
|
-
def matches?(query)
|
48
|
-
[name, screen_name, description, website].any? { |x| x.to_s.downcase.include? query.downcase }
|
49
|
-
end
|
50
|
-
|
51
|
-
def muted_by?(user_id)
|
52
|
-
Friendship.muting?(user_id, id)
|
53
|
-
end
|
54
|
-
|
55
|
-
def muting?(user_id)
|
56
|
-
Friendship.muting?(id, user_id)
|
57
|
-
end
|
58
|
-
|
59
|
-
def touch!
|
60
|
-
@touched_at = Time.now
|
61
15
|
end
|
62
16
|
|
63
17
|
def update!(user)
|
64
|
-
return self if recently_updated?
|
65
|
-
|
66
18
|
@name = user.name
|
67
19
|
@screen_name = user.screen_name
|
68
|
-
@description = user.description
|
20
|
+
@description = user.description.is_a?(Twitter::NullObject) ? '' : user.description
|
69
21
|
@location = user.location.is_a?(Twitter::NullObject) ? '' : user.location
|
70
22
|
@website = user.website
|
71
23
|
@protected = user.protected?
|
@@ -75,67 +27,7 @@ module Twterm
|
|
75
27
|
@followers_count = user.followers_count
|
76
28
|
@verified = user.verified?
|
77
29
|
|
78
|
-
client_id = Client.current.user_id
|
79
|
-
|
80
|
-
if user.following?
|
81
|
-
Friendship.follow(client_id, user.id)
|
82
|
-
else
|
83
|
-
Friendship.unfollow(client_id, user.id)
|
84
|
-
end
|
85
|
-
|
86
|
-
if user.follow_request_sent?
|
87
|
-
Friendship.following_requested(client_id, user.id)
|
88
|
-
else
|
89
|
-
Friendship.following_not_requested(client_id, user.id)
|
90
|
-
end
|
91
|
-
|
92
|
-
@updated_at = Time.now
|
93
|
-
|
94
30
|
self
|
95
31
|
end
|
96
|
-
|
97
|
-
def self.all
|
98
|
-
@@instances.values
|
99
|
-
end
|
100
|
-
|
101
|
-
def self.find(id)
|
102
|
-
@@instances[id]
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.find_or_fetch(id)
|
106
|
-
Promise.new do |resolve, reject|
|
107
|
-
instance = find(id)
|
108
|
-
(resolve.(instance) && next) if instance
|
109
|
-
|
110
|
-
Client.current.show_user(id).then do |user|
|
111
|
-
resolve.(user)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.cleanup
|
117
|
-
referenced_users = Status.all.map(&:user)
|
118
|
-
referenced_users.each(&:touch!)
|
119
|
-
|
120
|
-
cond = -> (user) { user.touched_at > Time.now - MAX_CACHED_TIME }
|
121
|
-
users = all.select(&cond)
|
122
|
-
user_ids = users.map(&:id)
|
123
|
-
@@instances = Hash[user_ids.zip(users)]
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.ids
|
127
|
-
@@instances.keys
|
128
|
-
end
|
129
|
-
|
130
|
-
def self.new(user)
|
131
|
-
instance = find(user.id)
|
132
|
-
instance.nil? ? super : instance.update!(user)
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
|
137
|
-
def recently_updated?
|
138
|
-
!@updated_at.nil? && @updated_at + 60 > Time.now
|
139
|
-
end
|
140
32
|
end
|
141
33
|
end
|
data/lib/twterm/version.rb
CHANGED
data/lib/twterm/view.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Twterm
|
2
|
+
class View
|
3
|
+
def initialize(window, image)
|
4
|
+
@window, @image = window, image
|
5
|
+
end
|
6
|
+
|
7
|
+
def at(line, column)
|
8
|
+
@line, @column = line, column
|
9
|
+
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
@image.at(line, column).render(@window)
|
15
|
+
@window.refresh
|
16
|
+
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def column
|
23
|
+
@column || 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def line
|
27
|
+
@line || 0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/twterm.rb
CHANGED
@@ -19,20 +19,14 @@ require 'twterm/client'
|
|
19
19
|
require 'twterm/color_manager'
|
20
20
|
require 'twterm/completion_mamanger'
|
21
21
|
require 'twterm/config'
|
22
|
+
require 'twterm/extensions/array'
|
22
23
|
require 'twterm/extensions/curses/window'
|
23
24
|
require 'twterm/extensions/enumerator/lazy'
|
24
|
-
require 'twterm/extensions/integer'
|
25
25
|
require 'twterm/extensions/string'
|
26
|
-
require 'twterm/
|
27
|
-
require 'twterm/filterable_list'
|
26
|
+
require 'twterm/search_query_window'
|
28
27
|
require 'twterm/friendship'
|
29
|
-
require 'twterm/history/base'
|
30
|
-
require 'twterm/history/savable'
|
31
|
-
require 'twterm/history/hashtag'
|
32
|
-
require 'twterm/history/screen_name'
|
33
28
|
require 'twterm/list'
|
34
29
|
require 'twterm/notifier'
|
35
|
-
require 'twterm/promise'
|
36
30
|
require 'twterm/screen'
|
37
31
|
require 'twterm/scheduler'
|
38
32
|
require 'twterm/status'
|
@@ -64,6 +58,6 @@ require 'twterm/version'
|
|
64
58
|
|
65
59
|
module Twterm
|
66
60
|
class Conf
|
67
|
-
REQUIRE_VERSION = '1.
|
61
|
+
REQUIRE_VERSION = '1.1.1'
|
68
62
|
end
|
69
63
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
{
|
2
|
+
"coordinates": null,
|
3
|
+
"favorited": false,
|
4
|
+
"truncated": false,
|
5
|
+
"created_at": "Wed Jun 06 20:07:10 +0000 2012",
|
6
|
+
"id_str": "210462857140252672",
|
7
|
+
"entities": {
|
8
|
+
"urls": [
|
9
|
+
{
|
10
|
+
"expanded_url": "/terms/display-guidelines",
|
11
|
+
"url": "https://t.co/Ed4omjYs",
|
12
|
+
"indices": [
|
13
|
+
76,
|
14
|
+
97
|
15
|
+
],
|
16
|
+
"display_url": "dev.twitter.com/terms/display-\u2026"
|
17
|
+
}
|
18
|
+
],
|
19
|
+
"hashtags": [
|
20
|
+
{
|
21
|
+
"text": "Twitterbird",
|
22
|
+
"indices": [
|
23
|
+
19,
|
24
|
+
31
|
25
|
+
]
|
26
|
+
}
|
27
|
+
],
|
28
|
+
"user_mentions": [
|
29
|
+
|
30
|
+
]
|
31
|
+
},
|
32
|
+
"in_reply_to_user_id_str": null,
|
33
|
+
"contributors": [
|
34
|
+
14927800
|
35
|
+
],
|
36
|
+
"text": "Along with our new #Twitterbird, we've also updated our Display Guidelines: https://t.co/Ed4omjYs ^JC",
|
37
|
+
"retweet_count": 66,
|
38
|
+
"in_reply_to_status_id_str": null,
|
39
|
+
"id": 210462857140252672,
|
40
|
+
"geo": null,
|
41
|
+
"retweeted": true,
|
42
|
+
"possibly_sensitive": false,
|
43
|
+
"in_reply_to_user_id": null,
|
44
|
+
"place": null,
|
45
|
+
"user": {
|
46
|
+
"profile_sidebar_fill_color": "DDEEF6",
|
47
|
+
"profile_sidebar_border_color": "C0DEED",
|
48
|
+
"profile_background_tile": false,
|
49
|
+
"name": "Twitter API",
|
50
|
+
"profile_image_url": "http://a0.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_normal.png",
|
51
|
+
"created_at": "Wed May 23 06:01:13 +0000 2007",
|
52
|
+
"location": "San Francisco, CA",
|
53
|
+
"follow_request_sent": false,
|
54
|
+
"profile_link_color": "0084B4",
|
55
|
+
"is_translator": false,
|
56
|
+
"id_str": "6253282",
|
57
|
+
"entities": {
|
58
|
+
"url": {
|
59
|
+
"urls": [
|
60
|
+
{
|
61
|
+
"expanded_url": null,
|
62
|
+
"url": "",
|
63
|
+
"indices": [
|
64
|
+
0,
|
65
|
+
22
|
66
|
+
]
|
67
|
+
}
|
68
|
+
]
|
69
|
+
},
|
70
|
+
"description": {
|
71
|
+
"urls": [
|
72
|
+
|
73
|
+
]
|
74
|
+
}
|
75
|
+
},
|
76
|
+
"default_profile": true,
|
77
|
+
"contributors_enabled": true,
|
78
|
+
"favourites_count": 24,
|
79
|
+
"url": "",
|
80
|
+
"profile_image_url_https": "https://si0.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_normal.png",
|
81
|
+
"utc_offset": -28800,
|
82
|
+
"id": 6253282,
|
83
|
+
"profile_use_background_image": true,
|
84
|
+
"listed_count": 10774,
|
85
|
+
"profile_text_color": "333333",
|
86
|
+
"lang": "en",
|
87
|
+
"followers_count": 1212963,
|
88
|
+
"protected": false,
|
89
|
+
"notifications": null,
|
90
|
+
"profile_background_image_url_https": "https://si0.twimg.com/images/themes/theme1/bg.png",
|
91
|
+
"profile_background_color": "C0DEED",
|
92
|
+
"verified": true,
|
93
|
+
"geo_enabled": true,
|
94
|
+
"time_zone": "Pacific Time (US & Canada)",
|
95
|
+
"description": "The Real Twitter API. I tweet about API changes, service issues and happily answer questions about Twitter and our API. Don't get an answer? It's on my website.",
|
96
|
+
"default_profile_image": false,
|
97
|
+
"profile_background_image_url": "http://a0.twimg.com/images/themes/theme1/bg.png",
|
98
|
+
"statuses_count": 3333,
|
99
|
+
"friends_count": 31,
|
100
|
+
"following": true,
|
101
|
+
"show_all_inline_media": false,
|
102
|
+
"screen_name": "twitterapi"
|
103
|
+
},
|
104
|
+
"in_reply_to_screen_name": null,
|
105
|
+
"source": "web",
|
106
|
+
"in_reply_to_status_id": null
|
107
|
+
}
|