twterm 1.3.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -18
  3. data/bin/twterm +1 -1
  4. data/lib/twterm/app.rb +120 -30
  5. data/lib/twterm/client.rb +10 -13
  6. data/lib/twterm/completion_mamanger.rb +11 -6
  7. data/lib/twterm/direct_message.rb +6 -28
  8. data/lib/twterm/direct_message_composer.rb +10 -5
  9. data/lib/twterm/direct_message_manager.rb +5 -6
  10. data/lib/twterm/event/notification/abstract_notification.rb +27 -0
  11. data/lib/twterm/event/notification/error.rb +13 -0
  12. data/lib/twterm/event/notification/info.rb +13 -0
  13. data/lib/twterm/event/notification/success.rb +13 -0
  14. data/lib/twterm/event/notification/warning.rb +13 -0
  15. data/lib/twterm/event_dispatcher.rb +1 -1
  16. data/lib/twterm/extensions/array.rb +5 -0
  17. data/lib/twterm/extensions/enumerator/lazy.rb +3 -0
  18. data/lib/twterm/extensions/string.rb +0 -4
  19. data/lib/twterm/friendship.rb +1 -85
  20. data/lib/twterm/image/between.rb +31 -0
  21. data/lib/twterm/image/blank_line.rb +21 -0
  22. data/lib/twterm/image/bold.rb +31 -0
  23. data/lib/twterm/image/brackets.rb +21 -0
  24. data/lib/twterm/image/color.rb +45 -0
  25. data/lib/twterm/image/empty.rb +21 -0
  26. data/lib/twterm/image/horizontal_sequential_image.rb +48 -0
  27. data/lib/twterm/image/parens.rb +21 -0
  28. data/lib/twterm/image/string_image.rb +38 -0
  29. data/lib/twterm/image/vertical_sequential_image.rb +43 -0
  30. data/lib/twterm/image.rb +107 -0
  31. data/lib/twterm/key_mapper/abstract_key_mapper.rb +51 -0
  32. data/lib/twterm/key_mapper/app_key_mapper.rb +13 -0
  33. data/lib/twterm/key_mapper/cursor_key_mapper.rb +13 -0
  34. data/lib/twterm/key_mapper/general_key_mapper.rb +18 -0
  35. data/lib/twterm/key_mapper/no_such_command.rb +20 -0
  36. data/lib/twterm/key_mapper/no_such_key.rb +16 -0
  37. data/lib/twterm/key_mapper/status_key_mapper.rb +18 -0
  38. data/lib/twterm/key_mapper/tab_key_mapper.rb +31 -0
  39. data/lib/twterm/key_mapper.rb +127 -0
  40. data/lib/twterm/list.rb +0 -31
  41. data/lib/twterm/notifier.rb +7 -7
  42. data/lib/twterm/repository/abstract_entity_repository.rb +41 -0
  43. data/lib/twterm/repository/abstract_expirable_entity_repository.rb +35 -0
  44. data/lib/twterm/repository/abstract_repository.rb +64 -0
  45. data/lib/twterm/repository/direct_message_repository.rb +14 -0
  46. data/lib/twterm/repository/friendship_repository.rb +108 -0
  47. data/lib/twterm/repository/hashtag_repository.rb +39 -0
  48. data/lib/twterm/repository/list_repository.rb +14 -0
  49. data/lib/twterm/repository/status_repository.rb +36 -0
  50. data/lib/twterm/repository/user_repository.rb +22 -0
  51. data/lib/twterm/rest_client.rb +107 -63
  52. data/lib/twterm/screen.rb +21 -15
  53. data/lib/twterm/search_query_window.rb +139 -0
  54. data/lib/twterm/status.rb +14 -108
  55. data/lib/twterm/streaming_client.rb +13 -12
  56. data/lib/twterm/tab/base.rb +48 -8
  57. data/lib/twterm/tab/direct_message/conversation.rb +53 -52
  58. data/lib/twterm/tab/direct_message/conversation_list.rb +46 -45
  59. data/lib/twterm/tab/dumpable.rb +3 -3
  60. data/lib/twterm/tab/key_assignments_cheatsheet.rb +58 -57
  61. data/lib/twterm/tab/loadable.rb +20 -0
  62. data/lib/twterm/tab/new/list.rb +32 -43
  63. data/lib/twterm/tab/new/search.rb +31 -44
  64. data/lib/twterm/tab/new/start.rb +44 -55
  65. data/lib/twterm/tab/new/user.rb +15 -12
  66. data/lib/twterm/tab/rate_limit_status.rb +84 -0
  67. data/lib/twterm/tab/scrollable.rb +39 -19
  68. data/lib/twterm/tab/searchable.rb +133 -0
  69. data/lib/twterm/tab/statuses/base.rb +139 -129
  70. data/lib/twterm/tab/statuses/conversation.rb +26 -15
  71. data/lib/twterm/tab/statuses/favorites.rb +10 -8
  72. data/lib/twterm/tab/statuses/home.rb +10 -9
  73. data/lib/twterm/tab/statuses/list_timeline.rb +12 -8
  74. data/lib/twterm/tab/statuses/mentions.rb +17 -11
  75. data/lib/twterm/tab/statuses/search.rb +8 -5
  76. data/lib/twterm/tab/statuses/user_timeline.rb +11 -8
  77. data/lib/twterm/tab/user_list_management.rb +109 -0
  78. data/lib/twterm/tab/user_tab.rb +125 -126
  79. data/lib/twterm/tab/users/base.rb +39 -41
  80. data/lib/twterm/tab/users/followers.rb +9 -6
  81. data/lib/twterm/tab/users/friends.rb +9 -6
  82. data/lib/twterm/tab_manager.rb +64 -40
  83. data/lib/twterm/tweetbox.rb +18 -13
  84. data/lib/twterm/uri_opener.rb +2 -1
  85. data/lib/twterm/user.rb +2 -110
  86. data/lib/twterm/version.rb +1 -1
  87. data/lib/twterm/view.rb +30 -0
  88. data/lib/twterm.rb +3 -9
  89. data/spec/fixtures/status.json +107 -0
  90. data/spec/fixtures/user.json +102 -0
  91. data/spec/spec_helper.rb +7 -0
  92. data/spec/supports/shared_examples/abstract_key_mapper.rb +17 -0
  93. data/spec/twterm/extension/enumerator/lazy_spec.rb +11 -0
  94. data/spec/twterm/friendship_spec.rb +0 -102
  95. data/spec/twterm/image/blank_line_spec.rb +11 -0
  96. data/spec/twterm/image/brackets_spec.rb +12 -0
  97. data/spec/twterm/image/color_spec.rb +22 -0
  98. data/spec/twterm/image/empry_spec.rb +11 -0
  99. data/spec/twterm/image/horizontal_sequential_image_spec.rb +15 -0
  100. data/spec/twterm/image/parens_spec.rb +12 -0
  101. data/spec/twterm/image/string_image_spec.rb +12 -0
  102. data/spec/twterm/image/vertical_sequential_image_spec.rb +14 -0
  103. data/spec/twterm/image_spec.rb +65 -0
  104. data/spec/twterm/key_mapper/abstract_key_mapper_spec.rb +21 -0
  105. data/spec/twterm/key_mapper/app_key_mapper_spec.rb +7 -0
  106. data/spec/twterm/key_mapper/status_key_mapper_spec.rb +7 -0
  107. data/spec/twterm/key_mapper/tab_key_mapper_spec.rb +7 -0
  108. data/spec/twterm/repository/friendship_repository_spec.rb +108 -0
  109. data/spec/twterm/status_spec.rb +58 -0
  110. data/spec/twterm/user_spec.rb +94 -0
  111. data/twterm.gemspec +13 -10
  112. metadata +129 -35
  113. data/lib/twterm/event/notification.rb +0 -33
  114. data/lib/twterm/extensions/integer.rb +0 -5
  115. data/lib/twterm/filter_query_window.rb +0 -91
  116. data/lib/twterm/filterable_list.rb +0 -41
  117. data/lib/twterm/history/base.rb +0 -21
  118. data/lib/twterm/history/hashtag.rb +0 -13
  119. data/lib/twterm/history/savable.rb +0 -37
  120. data/lib/twterm/history/screen_name.rb +0 -11
  121. data/lib/twterm/promise.rb +0 -143
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 224b8dc2d3619a2042816816273a0526a7cb9666
4
- data.tar.gz: f1e33882f1154a83dfb5c744d1d613f4844aba48
3
+ metadata.gz: 064c6b973d192af1687649528910f091550c24ed
4
+ data.tar.gz: e7c65c16eb7c113e68b3f8aa9d03fcfafbe703d4
5
5
  SHA512:
6
- metadata.gz: 57087dc1e7f65520af3ab90af85e7d8511855ca40696709173e8797aa2d1a004fba09dd2eebcb6ce8dd03cceaf03d530a8f5ad827a6ed318e05fb5940db644ee
7
- data.tar.gz: 204684237b545673c87f0edb02fbf80b7c077095b59531ba5b1c43ff1055ccee7585354d9612dee02cf54fa88ebbaca72d250f81418c2d4a3c8d6153d1aa63ae
6
+ metadata.gz: eaa76b8503cd6749d4df7ac6e261ebeb13b1a59cef56d5aba5e327e0946013e46a180a3c5d424cbb8590adba4440e91be3234b78e91564b35e6555afa942c9e2
7
+ data.tar.gz: 6c92404ae8e51b1867efe30d93bf5bbd2a51ee4dfb06d6e02d8449913222b5d6bda82f7a98fac416718ac19bfad75743e6a428c54fd86fd816e6e0f968eed679
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # twterm
2
2
 
3
- A full-featured CLI Twitter client
3
+ A full-featured TUI Twitter client
4
4
 
5
5
  ## Screenshot
6
6
 
@@ -8,8 +8,8 @@ A full-featured CLI Twitter client
8
8
 
9
9
  ## Requirements
10
10
 
11
- - Ruby (>= 2.1, compiled with C Curses and Readline)
12
- - C curses
11
+ - Ruby (>= 2.1, compiled with ncurses and Readline)
12
+ - ncurses
13
13
  - Readline
14
14
 
15
15
  ## Installation
@@ -26,25 +26,21 @@ To launch twterm, just type in your console:
26
26
  $ twterm
27
27
  ```
28
28
 
29
- ### Basic key assignments
29
+ ### Default key assignments
30
+
31
+ Key assignments can be configured by editing `~/.twterm/keys.toml`
30
32
 
31
33
  key | operation
32
34
  --- | ---
33
- `F` | add to favorite
34
- `d` `C-d` | scroll down
35
- `h` `C-b` `←` | show previous tab
36
- `j` `C-n` `↓` | move down
37
- `k` `C-p` `↑` | move up
38
- `l` `C-f` `→` | show next tab
39
- `n` | compose new tweet
40
- `N` | open new tab
41
- `r` | reply
42
- `R` | retweet
35
+ `h` `←` | previous tab
36
+ `j` `↓` | move down
37
+ `k` `↑` | move up
38
+ `l` `→` | next tab
39
+ `^N` | new tweet
40
+ `^T` | new tab
43
41
  `w` | close current tab
44
- `Q` | quit
45
- `?` | open key assignments cheatsheet
46
-
47
- Type `?` key to see the full list of key assignments.
42
+ `F10` | quit
43
+ `F1` | key assignments cheatsheet
48
44
 
49
45
  ## License
50
46
 
data/bin/twterm CHANGED
@@ -6,5 +6,5 @@ if ARGV.count == 1 && (%w(-v --version).include?(ARGV.first))
6
6
  exit
7
7
  else
8
8
  require 'twterm'
9
- Twterm::App.instance.run
9
+ Twterm::App.new.run
10
10
  end
data/lib/twterm/app.rb CHANGED
@@ -1,55 +1,120 @@
1
1
  require 'curses'
2
+
3
+ require 'twterm/completion_mamanger'
4
+ require 'twterm/direct_message_composer'
2
5
  require 'twterm/event/screen/resize'
6
+ require 'twterm/repository/direct_message_repository'
7
+ require 'twterm/repository/friendship_repository'
8
+ require 'twterm/repository/hashtag_repository'
9
+ require 'twterm/repository/list_repository'
10
+ require 'twterm/repository/status_repository'
11
+ require 'twterm/repository/user_repository'
12
+ require 'twterm/tab_manager'
13
+ require 'twterm/tweetbox'
3
14
  require 'twterm/uri_opener'
4
15
 
5
16
  module Twterm
6
17
  class App
7
18
  include Publisher
8
- include Singleton
19
+
20
+ attr_reader :screen
9
21
 
10
22
  DATA_DIR = "#{ENV['HOME']}/.twterm".freeze
11
23
 
12
- def initialize
24
+ def completion_manager
25
+ @completion_mamanger ||= CompletionManager.new(self)
26
+ end
27
+
28
+ def direct_message_composer
29
+ @direct_message_composer ||= DirectMessageComposer.new(self, client)
30
+ end
31
+
32
+ def direct_message_repository
33
+ @direct_messages_repository ||= Repository::DirectMessageRepository.new
34
+ end
35
+
36
+ def friendship_repository
37
+ @friendship_repository ||= Repository::FriendshipRepository.new
38
+ end
39
+
40
+ def hashtag_repository
41
+ @hashtag_repository ||= Repository::HashtagRepository.new
42
+ end
43
+
44
+ def list_repository
45
+ @list_repository ||= Repository::ListRepository.new
46
+ end
47
+
48
+ def run
13
49
  Dir.mkdir(DATA_DIR, 0700) unless File.directory?(DATA_DIR)
14
50
 
15
51
  Auth.authenticate_user(config) if config[:user_id].nil?
16
52
 
17
- Screen.instance
18
- FilterQueryWindow.instance
53
+ KeyMapper.instance
19
54
 
20
- timeline = Tab::Statuses::Home.new(client)
21
- TabManager.instance.add_and_show(timeline)
55
+ @screen = Screen.new(self, client)
22
56
 
23
- mentions_tab = Tab::Statuses::Mentions.new(client)
57
+ SearchQueryWindow.instance
24
58
 
25
- TabManager.instance.add(mentions_tab)
26
- TabManager.instance.recover_tabs
59
+ timeline = Tab::Statuses::Home.new(self, client)
60
+ tab_manager.add_and_show(timeline)
27
61
 
28
- Screen.instance.refresh
62
+ mentions_tab = Tab::Statuses::Mentions.new(self, client)
63
+
64
+ tab_manager.add(mentions_tab)
65
+ tab_manager.recover_tabs
66
+
67
+ screen.refresh
29
68
 
30
69
  client.connect_user_stream
31
70
 
32
71
  reset_interruption_handler
33
72
 
73
+ Signal.trap(:WINCH) { on_resize }
74
+ Scheduler.new(60) { on_resize }
75
+
34
76
  URIOpener.instance
35
77
 
36
- resize = proc do
37
- next if Curses.closed?
78
+ Scheduler.new(300) do
79
+ status_repository.expire(3600)
38
80
 
39
- lines = `tput lines`.to_i
40
- cols = `tput cols`.to_i
41
- publish(Event::Screen::Resize.new(lines, cols))
81
+ _ = status_repository.all.map { |user_id| user_repository.find(user_id) }
82
+ user_repository.expire(3600)
42
83
  end
43
84
 
44
- Signal.trap(:WINCH, &resize)
45
- Scheduler.new(60, &resize)
46
- end
85
+ direct_message_repository.before_create do |dm|
86
+ user_repository.create(dm.recipient)
87
+ user_repository.create(dm.sender)
88
+ end
47
89
 
48
- def run
49
- run_periodic_cleanup
90
+ user_repository.before_create do |user|
91
+ client_id = client.user_id
92
+
93
+ if user.following?
94
+ friendship_repository.follow(client_id, user.id)
95
+ else
96
+ friendship_repository.unfollow(client_id, user.id)
97
+ end
98
+
99
+ if user.follow_request_sent?
100
+ friendship_repository.following_requested(client_id, user.id)
101
+ else
102
+ friendship_repository.following_not_requested(client_id, user.id)
103
+ end
104
+ end
50
105
 
51
- Screen.instance.wait
52
- Screen.instance.refresh
106
+ status_repository.before_create do |tweet|
107
+ user_repository.create(tweet.user)
108
+ end
109
+
110
+ status_repository.before_create do |tweet|
111
+ tweet.hashtags.each do |hashtag|
112
+ hashtag_repository.create(hashtag.text)
113
+ end
114
+ end
115
+
116
+ screen.wait
117
+ screen.refresh
53
118
  end
54
119
 
55
120
  def register_interruption_handler(&block)
@@ -58,15 +123,31 @@ module Twterm
58
123
  end
59
124
 
60
125
  def reset_interruption_handler
61
- Signal.trap(:INT) { App.instance.quit }
126
+ Signal.trap(:INT) { quit }
62
127
  end
63
128
 
64
129
  def quit
65
130
  Curses.close_screen
66
- TabManager.instance.dump_tabs
131
+ tab_manager.dump_tabs
67
132
  exit
68
133
  end
69
134
 
135
+ def status_repository
136
+ @status_repository ||= Repository::StatusRepository.new
137
+ end
138
+
139
+ def tab_manager
140
+ @tab_manager ||= TabManager.new(self, client)
141
+ end
142
+
143
+ def tweetbox
144
+ @tweetbox = Tweetbox.new(self, client)
145
+ end
146
+
147
+ def user_repository
148
+ @user_repository ||= Repository::UserRepository.new
149
+ end
150
+
70
151
  private
71
152
 
72
153
  def client
@@ -74,7 +155,15 @@ module Twterm
74
155
  config[:user_id].to_i,
75
156
  config[:screen_name],
76
157
  config[:access_token],
77
- config[:access_token_secret]
158
+ config[:access_token_secret],
159
+ {
160
+ friendship: friendship_repository,
161
+ direct_message: direct_message_repository,
162
+ hashtag: hashtag_repository,
163
+ list: list_repository,
164
+ status: status_repository,
165
+ user: user_repository,
166
+ }
78
167
  )
79
168
  end
80
169
 
@@ -82,11 +171,12 @@ module Twterm
82
171
  @config ||= Config.new
83
172
  end
84
173
 
85
- def run_periodic_cleanup
86
- Scheduler.new(300) do
87
- Status.cleanup
88
- User.cleanup
89
- end
174
+ def on_resize
175
+ return if Curses.closed?
176
+
177
+ lines = `tput lines`.to_i
178
+ cols = `tput cols`.to_i
179
+ publish(Event::Screen::Resize.new(lines, cols))
90
180
  end
91
181
  end
92
182
  end
data/lib/twterm/client.rb CHANGED
@@ -8,12 +8,17 @@ module Twterm
8
8
 
9
9
  attr_reader :user_id, :screen_name
10
10
 
11
- @@instances = []
12
-
13
- def initialize(user_id, screen_name, access_token, access_token_secret)
11
+ def initialize(user_id, screen_name, access_token, access_token_secret, repositories)
14
12
  @user_id, @screen_name = user_id, screen_name
15
13
  @access_token, @access_token_secret = access_token, access_token_secret
16
14
 
15
+ @friendship_repository = repositories[:friendship]
16
+ @direct_message_repository = repositories[:direct_message]
17
+ @hashtag_repository = repositories[:hashtag]
18
+ @list_repository = repositories[:list]
19
+ @status_repository = repositories[:status]
20
+ @user_repository = repositories[:user]
21
+
17
22
  @callbacks = {}
18
23
 
19
24
  @mute_filter = -> _ { true }
@@ -26,18 +31,10 @@ module Twterm
26
31
  end
27
32
 
28
33
  direct_message_manager
29
-
30
- @@instances << self
31
34
  end
32
35
 
33
- def self.new(user_id, screen_name, token, secret)
34
- detector = -> (instance) { instance.user_id == user_id }
35
- instance = @@instances.find(&detector)
36
- instance.nil? ? super : instance
37
- end
36
+ private
38
37
 
39
- def self.current
40
- @@instances[0]
41
- end
38
+ attr_reader :friendship_repository, :direct_message_repository, :hashtag_repository, :list_repository, :status_repository, :user_repository
42
39
  end
43
40
  end
@@ -1,8 +1,8 @@
1
1
  module Twterm
2
2
  class CompletionManager
3
- include Singleton
3
+ def initialize(app)
4
+ @app = app
4
5
 
5
- def initialize
6
6
  Readline.basic_word_break_characters = " \t\n\"\\'`$><=;|&{("
7
7
  Readline.completion_case_fold = false
8
8
  end
@@ -12,12 +12,12 @@ module Twterm
12
12
 
13
13
  Readline.completion_proc = proc do |str|
14
14
  if str.start_with?('#')
15
- History::Hashtag.instance.history
15
+ app.hashtag_repository.all
16
16
  .map { |tag| "##{tag}" }
17
17
  .select { |tag| tag.start_with?(str) }
18
18
  elsif str.start_with?('@')
19
- History::ScreenName.instance.history
20
- .map { |name| "@#{name}" }
19
+ app.user_repository.all
20
+ .map { |user| "@#{user.screen_name}" }
21
21
  .select { |name| name.start_with?(str) }
22
22
  else
23
23
  []
@@ -29,9 +29,14 @@ module Twterm
29
29
  Readline.completion_append_character = ''
30
30
 
31
31
  Readline.completion_proc = proc do |str|
32
- History::ScreenName.instance.history
32
+ app.user_repository.all
33
+ .map { |user| user.screen_name }
33
34
  .select { |name| name.start_with?(str) }
34
35
  end
35
36
  end
37
+
38
+ private
39
+
40
+ attr_reader :app
36
41
  end
37
42
  end
@@ -3,15 +3,11 @@ require 'twterm/utils'
3
3
 
4
4
  module Twterm
5
5
  class DirectMessage
6
- attr_reader :id, :created_at, :recipient, :sender, :text
7
-
8
- @@instances = {}
6
+ attr_reader :id, :created_at, :recipient_id, :sender_id, :text
9
7
 
10
8
  def initialize(message)
11
9
  @id = message.id
12
10
  update!(message)
13
-
14
- @@instances[id] = self
15
11
  end
16
12
 
17
13
  def ==(other)
@@ -23,18 +19,10 @@ module Twterm
23
19
  @created_at.strftime(format)
24
20
  end
25
21
 
26
- def matches?(q)
27
- [
28
- sender.name,
29
- sender.screen_name,
30
- text
31
- ].map(&:downcase).any? { |x| x.include?(q) }
32
- end
33
-
34
22
  def update!(message)
35
23
  @created_at = message.created_at.dup.localtime
36
- @recipient = User.new(message.recipient)
37
- @sender = User.new(message.sender)
24
+ @recipient_id = message.recipient.id
25
+ @sender_id = message.sender.id
38
26
  @text = message.text
39
27
 
40
28
  self
@@ -43,12 +31,10 @@ module Twterm
43
31
  class Conversation
44
32
  include Utils
45
33
 
46
- attr_reader :collocutor, :messages
34
+ attr_reader :collocutor_id, :messages
47
35
 
48
- def initialize(collocutor)
49
- check_type User, collocutor
50
-
51
- @collocutor = collocutor
36
+ def initialize(collocutor_id)
37
+ @collocutor_id = collocutor_id
52
38
  @messages = []
53
39
  end
54
40
 
@@ -59,14 +45,6 @@ module Twterm
59
45
  self
60
46
  end
61
47
 
62
- def matches?(q)
63
- [
64
- collocutor.screen_name,
65
- collocutor.name,
66
- preview
67
- ].map(&:downcase).any? { |x| x.include?(q.downcase) }
68
- end
69
-
70
48
  def preview
71
49
  messages.sort_by(&:created_at).last.text.gsub("\n", ' ')
72
50
  end
@@ -4,12 +4,15 @@ require 'twterm/utils'
4
4
 
5
5
  module Twterm
6
6
  class DirectMessageComposer
7
- include Singleton
8
7
  include Readline
9
8
  include Curses
10
9
  include Publisher
11
10
  include Utils
12
11
 
12
+ def initialize(app, client)
13
+ @app, @client = app, client
14
+ end
15
+
13
16
  def compose(recipient)
14
17
  check_type User, recipient
15
18
 
@@ -18,7 +21,7 @@ module Twterm
18
21
  resetter = proc do
19
22
  reset_prog_mode
20
23
  sleep 0.1
21
- Screen.instance.refresh
24
+ app.screen.refresh
22
25
  end
23
26
 
24
27
  thread = Thread.new do
@@ -26,7 +29,7 @@ module Twterm
26
29
 
27
30
  puts "\nCompose new message to @%s:" % recipient.screen_name
28
31
 
29
- CompletionManager.instance.set_default_mode!
32
+ app.completion_manager.set_default_mode!
30
33
 
31
34
  loop do
32
35
  line = (readline('> ', true) || '').strip
@@ -46,7 +49,7 @@ module Twterm
46
49
  send(recipient) unless text.empty?
47
50
  end
48
51
 
49
- App.instance.register_interruption_handler do
52
+ app.register_interruption_handler do
50
53
  thread.kill
51
54
  clear
52
55
  puts "\nCanceled"
@@ -58,12 +61,14 @@ module Twterm
58
61
 
59
62
  private
60
63
 
64
+ attr_reader :app, :client
65
+
61
66
  def clear
62
67
  @text = ''
63
68
  end
64
69
 
65
70
  def send(recipient)
66
- Client.current.create_direct_message(recipient, text)
71
+ client.create_direct_message(recipient, text)
67
72
  clear
68
73
  end
69
74
 
@@ -21,22 +21,21 @@ module Twterm
21
21
  Scheduler.new(300) { fetch }
22
22
  end
23
23
 
24
- def add(collocutor, message)
25
- check_type User, collocutor
24
+ def add(collocutor_id, message)
26
25
  check_type DirectMessage, message
27
26
 
28
- @conversations[collocutor.id] ||= DirectMessage::Conversation.new(collocutor)
29
- @conversations[collocutor.id] << message
27
+ @conversations[collocutor_id] ||= DirectMessage::Conversation.new(collocutor_id)
28
+ @conversations[collocutor_id] << message
30
29
  end
31
30
 
32
31
  def fetch
33
32
  client.direct_messages_received.then do |messages|
34
- messages.each { |m| add(m.sender, m) }
33
+ messages.each { |m| add(m.sender_id, m) }
35
34
  publish(Event::DirectMessage::Fetched.new)
36
35
  end
37
36
 
38
37
  client.direct_messages_sent.then do |messages|
39
- messages.each { |m| add(m.recipient, m) }
38
+ messages.each { |m| add(m.recipient_id, m) }
40
39
  publish(Event::DirectMessage::Fetched.new)
41
40
  end
42
41
  end
@@ -0,0 +1,27 @@
1
+ require 'twterm/event/base'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class AbstractNotification < Twterm::Event::Base
7
+ attr_reader :time
8
+
9
+ def initialize(message)
10
+ super(CGI.unescapeHTML(message))
11
+
12
+ @time = Time.now
13
+ end
14
+
15
+ def fields
16
+ {
17
+ message: String
18
+ }
19
+ end
20
+
21
+ def color
22
+ raise NotImplementedError, 'color method must be overridden'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class Error < AbstractNotification
7
+ def color
8
+ [:white, :red]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class Info < AbstractNotification
7
+ def color
8
+ [:black, :cyan]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class Success < AbstractNotification
7
+ def color
8
+ [:black, :green]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class Warning < AbstractNotification
7
+ def color
8
+ [:black, :yellow]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -12,7 +12,7 @@ module Twterm
12
12
 
13
13
  def dispatch(event)
14
14
  @subscriptions
15
- .select { |s| s.event == event.class }
15
+ .select { |s| event.is_a?(s.event) }
16
16
  .map(&:callback)
17
17
  .each { |cb| cb.call(event) }
18
18
 
@@ -0,0 +1,5 @@
1
+ class Array
2
+ def intersperse(x)
3
+ ([x] * length).zip(self).flatten(1).drop(1)
4
+ end
5
+ end
@@ -3,7 +3,10 @@ class Enumerator
3
3
  def scan(initial, sym = nil)
4
4
  acc = initial
5
5
 
6
+ @_scan_has_yielded_initial_value = false
7
+
6
8
  Enumerator::Lazy.new(self) do |y, x|
9
+ y << initial && @_scan_has_yielded_initial_value = true unless @_scan_has_yielded_initial_value
7
10
  acc = sym.nil? ? yield(acc, x) : sym.to_proc.call(acc, x)
8
11
  y << acc
9
12
  end
@@ -3,10 +3,6 @@ class String
3
3
  each_char.map { |c| c.bytesize == 1 ? 1 : 2 }.reduce(0, &:+)
4
4
  end
5
5
 
6
- def matches?(query)
7
- downcase.include?(query.downcase)
8
- end
9
-
10
6
  def split_by_width(width)
11
7
  cnt = 0
12
8
  str = ''