twterm 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +4 -1
  3. data/lib/twterm.rb +1 -1
  4. data/lib/twterm/abstract_persistable_configuration.rb +118 -0
  5. data/lib/twterm/app.rb +21 -1
  6. data/lib/twterm/environment.rb +38 -0
  7. data/lib/twterm/event/message/abstract_message.rb +23 -0
  8. data/lib/twterm/event/message/error.rb +10 -0
  9. data/lib/twterm/event/message/info.rb +10 -0
  10. data/lib/twterm/event/message/success.rb +10 -0
  11. data/lib/twterm/event/message/warning.rb +10 -0
  12. data/lib/twterm/event/notification/abstract_notification.rb +17 -12
  13. data/lib/twterm/event/notification/direct_message.rb +30 -0
  14. data/lib/twterm/event/notification/favorite.rb +35 -0
  15. data/lib/twterm/event/notification/follow.rb +33 -0
  16. data/lib/twterm/event/notification/list_member_added.rb +33 -0
  17. data/lib/twterm/event/notification/mention.rb +35 -0
  18. data/lib/twterm/event/notification/quote.rb +35 -0
  19. data/lib/twterm/event/notification/retweet.rb +35 -0
  20. data/lib/twterm/key_mapper/abstract_key_mapper.rb +4 -4
  21. data/lib/twterm/list.rb +2 -1
  22. data/lib/twterm/message_window.rb +81 -0
  23. data/lib/twterm/notification_backend/abstract_notification_backend.rb +16 -0
  24. data/lib/twterm/notification_backend/inline_backend.rb +20 -0
  25. data/lib/twterm/notification_backend/terminal_notifier_backend.rb +23 -0
  26. data/lib/twterm/notification_backend/tmux_backend.rb +17 -0
  27. data/lib/twterm/notification_dispatcher.rb +36 -0
  28. data/lib/twterm/persistable_configuration_proxy.rb +82 -0
  29. data/lib/twterm/preferences.rb +66 -0
  30. data/lib/twterm/repository/abstract_expirable_entity_repository.rb +1 -1
  31. data/lib/twterm/rest_client.rb +12 -14
  32. data/lib/twterm/scheduler.rb +1 -1
  33. data/lib/twterm/screen.rb +1 -1
  34. data/lib/twterm/search_query_window.rb +2 -2
  35. data/lib/twterm/streaming_client.rb +54 -17
  36. data/lib/twterm/tab/base.rb +2 -3
  37. data/lib/twterm/tab/new/list.rb +2 -4
  38. data/lib/twterm/tab/new/start.rb +10 -0
  39. data/lib/twterm/tab/new/user.rb +2 -2
  40. data/lib/twterm/tab/preferences/index.rb +74 -0
  41. data/lib/twterm/tab/preferences/notification_backend.rb +85 -0
  42. data/lib/twterm/tab/scrollable.rb +0 -1
  43. data/lib/twterm/tab/searchable.rb +7 -7
  44. data/lib/twterm/tab/user_list_management.rb +3 -3
  45. data/lib/twterm/tab/user_tab.rb +6 -8
  46. data/lib/twterm/tab_manager.rb +4 -4
  47. data/lib/twterm/tweetbox.rb +1 -1
  48. data/lib/twterm/uri_opener.rb +2 -2
  49. data/lib/twterm/user.rb +2 -1
  50. data/lib/twterm/version.rb +1 -1
  51. data/twterm.gemspec +4 -2
  52. metadata +59 -14
  53. data/lib/twterm/event/favorite.rb +0 -18
  54. data/lib/twterm/event/follow.rb +0 -17
  55. data/lib/twterm/event/notification/error.rb +0 -13
  56. data/lib/twterm/event/notification/info.rb +0 -13
  57. data/lib/twterm/event/notification/success.rb +0 -13
  58. data/lib/twterm/event/notification/warning.rb +0 -13
  59. data/lib/twterm/notifier.rb +0 -82
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a822edd0e5719ca957ab183b1859bd6ec01113ca
4
- data.tar.gz: ecec2ab95f599a575226d0a3239f1b93ef63a4f9
2
+ SHA256:
3
+ metadata.gz: bce2d4276a631793204a44044b38afaa43f02d2c16bcc6daf68653288d1c5e12
4
+ data.tar.gz: e1307f6b9623eb96f2659406377888283d5a912fd30caf0d20737852a62e9b9c
5
5
  SHA512:
6
- metadata.gz: 1608685c830f8f614bc6549b498c271b7851deb05ee2e7054b62857ff89dae64f0d17f9f3d1fc22338493644aa35c9d4beb78c7ee2f6054eecd939108255d216
7
- data.tar.gz: f188471c3974d031c257b2a6fd9169926d1350b663d4b71ce4ee180d20e6d63a2a61657c1755e019c01ca38f1402493d386b53cb4e4e90b752051969e184ecf0
6
+ metadata.gz: 43c9cce69344a7e7cc8107793bc79f133ffe1ff134ec422eacbae4ae449661c0b57e7f6b15a241bb5d69db4c58d6bc22065badc9b85f1203bc29e130d8711fb9
7
+ data.tar.gz: fdad1dfb3aff8e7f66a94d00db63e5bd3d1e274072c17664e23ebb3de0a38dc26ebc2f9229f8172b14e84c1d71971cea05aba7ca9133eb7f537f03c33dbc8508
data/.travis.yml CHANGED
@@ -5,5 +5,8 @@ rvm:
5
5
  - 2.2
6
6
  - 2.3.0
7
7
  - 2.4.0
8
+ - 2.5.0
8
9
 
9
- script: bundle exec rspec
10
+ before_install: gem update --system
11
+
12
+ script: bundle exec rubocop --parallel --fail-level warning && bundle exec rspec
data/lib/twterm.rb CHANGED
@@ -26,7 +26,7 @@ require 'twterm/extensions/string'
26
26
  require 'twterm/search_query_window'
27
27
  require 'twterm/friendship'
28
28
  require 'twterm/list'
29
- require 'twterm/notifier'
29
+ require 'twterm/message_window'
30
30
  require 'twterm/screen'
31
31
  require 'twterm/scheduler'
32
32
  require 'twterm/status'
@@ -0,0 +1,118 @@
1
+ module Twterm
2
+ # @abstract
3
+ class AbstractPersistableConfiguration
4
+ # @param [Hash<Symbol, Object>] configuration A hash object to initialize configuration
5
+ def initialize(configuration = {})
6
+ @configuration = configuration
7
+ end
8
+
9
+ # Gets a value associated to the given key.
10
+ # @abstract
11
+ def [](*)
12
+ raise NotImplementedError, '`#[]` method must be implemented'
13
+ end
14
+
15
+ # Sets the given value to the given key.
16
+ # @abstract
17
+ def []=(*)
18
+ raise NotImplementedError, '`#[]=` method must be implemented'
19
+ end
20
+
21
+ # Returns the default instance for the configuration.
22
+ # @abstract
23
+ def self.default
24
+ raise NotImplementedError, '`.default` method must be implemented'
25
+ end
26
+
27
+ # @return [Boolean]
28
+ def self.has_same_structure?
29
+ true
30
+ end
31
+
32
+ # @return [self]
33
+ def complete_missing_items!
34
+ traverse(self.class.default.to_h) do |path, default_value|
35
+ value = dig(configuration, path)
36
+
37
+ if value.nil? || !(dig!(self.class.structure, path) === value)
38
+ bury!(path, default_value)
39
+ end
40
+ end
41
+
42
+ self
43
+ end
44
+
45
+ # Converts to a hash object.
46
+ #
47
+ # @abstract
48
+ # @return [Hash] Configuration as a hash
49
+ def to_h
50
+ raise NotImplementedError, '`#to_h` method must be implemented'
51
+ end
52
+
53
+ # A tree-like object representing the structure of the configuration.
54
+ # Each node must respond to {#===} method which determines whether a value is acceptable.
55
+ #
56
+ # @abstract
57
+ # @return [Hash] A tree-like hash object
58
+ def self.structure
59
+ raise NotImplementedError, '`.structure` method must be implemented'
60
+ end
61
+
62
+ private
63
+
64
+ attr_reader :configuration
65
+
66
+ def bury!(path, value)
67
+ go = lambda do |hash, rest_path|
68
+ k, *ks = rest_path
69
+
70
+ if ks.empty?
71
+ hash[k] = value
72
+ else
73
+ hash[k] = {} unless hash[k].is_a?(Hash)
74
+ go.call(hash[k], ks)
75
+ end
76
+ end
77
+
78
+ go.call(configuration, path)
79
+
80
+ configuration
81
+ end
82
+
83
+ def dig(hash, path)
84
+ k, *ks = path
85
+ ks.empty? ? hash[k] : dig(hash[k], ks)
86
+ rescue NoMethodError
87
+ nil
88
+ end
89
+
90
+ def dig!(hash, path)
91
+ k, *ks = path
92
+ ks.empty? ? hash[k] : dig(hash[k], ks)
93
+ rescue NoMethodError
94
+ raise ArgumentError, "path #{path} not found for hash #{hash}"
95
+ end
96
+
97
+ # Traverses tree-like {Hash} object and calls the given block on every node with its path
98
+ #
99
+ # @yieldparam [Array<Symbol>] path the path of the current node
100
+ # @yieldparam [Object] v the value of the current node
101
+ # @yieldreturn [void]
102
+ def traverse(tree, &f)
103
+ go = lambda do |subtree, current_path|
104
+ subtree.each do |k, v|
105
+ path = [*current_path, k]
106
+
107
+ if v.is_a?(Hash)
108
+ go.call(v, path)
109
+ else
110
+ f.call(path, v)
111
+ end
112
+ end
113
+ end
114
+
115
+ go.call(tree, [])
116
+ end
117
+ end
118
+ end
data/lib/twterm/app.rb CHANGED
@@ -2,7 +2,12 @@ require 'curses'
2
2
 
3
3
  require 'twterm/completion_manager'
4
4
  require 'twterm/direct_message_composer'
5
+ require 'twterm/environment'
5
6
  require 'twterm/event/screen/resize'
7
+ require 'twterm/message_window'
8
+ require 'twterm/notification_dispatcher'
9
+ require 'twterm/persistable_configuration_proxy'
10
+ require 'twterm/preferences'
6
11
  require 'twterm/repository/direct_message_repository'
7
12
  require 'twterm/repository/friendship_repository'
8
13
  require 'twterm/repository/hashtag_repository'
@@ -17,10 +22,20 @@ module Twterm
17
22
  class App
18
23
  include Publisher
19
24
 
20
- attr_reader :screen
25
+ attr_reader :environment, :preferences, :screen
21
26
 
22
27
  DATA_DIR = "#{ENV['HOME']}/.twterm".freeze
23
28
 
29
+ def initialize
30
+ @environment = Environment.new
31
+ @preferences = Preferences.default
32
+ end
33
+
34
+ def load_preferences_from_file!
35
+ @preferences = PersistableConfigurationProxy
36
+ .load_from_file!(Preferences, "#{DATA_DIR}/preferences.toml")
37
+ end
38
+
24
39
  def completion_manager
25
40
  @completion_manager ||= CompletionManager.new(self)
26
41
  end
@@ -50,11 +65,16 @@ module Twterm
50
65
 
51
66
  Auth.authenticate_user(config) if config[:user_id].nil?
52
67
 
68
+ load_preferences_from_file!
69
+
53
70
  KeyMapper.instance
54
71
 
55
72
  @screen = Screen.new(self, client)
56
73
 
57
74
  SearchQueryWindow.instance
75
+ MessageWindow.instance
76
+
77
+ @notification_dispatcher = NotificationDispatcher.new(preferences)
58
78
 
59
79
  timeline = Tab::Statuses::Home.new(self, client)
60
80
  tab_manager.add_and_show(timeline)
@@ -0,0 +1,38 @@
1
+ require 'terminal-notifier'
2
+
3
+ module Twterm
4
+ class Environment
5
+ def initialize
6
+ @uname = `uname`.strip
7
+
8
+ @terminal_notifier_available = TerminalNotifier.available?
9
+ @with_eog = system('which eog 2>&1 >/dev/null')
10
+ @with_tmux = system('which tmux 2>&1 >/dev/null') && !ENV['TMUX'].nil?
11
+ @with_qlmanage = system('which qlmanage 2>&1 >/dev/null')
12
+ end
13
+
14
+ def darwin?
15
+ @uname == 'Darwin'
16
+ end
17
+
18
+ def linux?
19
+ @uname == 'Linux'
20
+ end
21
+
22
+ def terminal_notifier_available?
23
+ @terminal_notifier_available
24
+ end
25
+
26
+ def with_eog?
27
+ @with_eog
28
+ end
29
+
30
+ def with_qlmanage?
31
+ @with_qlmanage
32
+ end
33
+
34
+ def with_tmux?
35
+ @with_tmux
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ require 'twterm/event/base'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Message
6
+ class AbstractMessage < 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
+ body: String
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ require 'twterm/event/message/abstract_message'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Message
6
+ class Error < AbstractMessage
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'twterm/event/message/abstract_message'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Message
6
+ class Info < AbstractMessage
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'twterm/event/message/abstract_message'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Message
6
+ class Success < AbstractMessage
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'twterm/event/message/abstract_message'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Message
6
+ class Warning < AbstractMessage
7
+ end
8
+ end
9
+ end
10
+ end
@@ -3,23 +3,28 @@ require 'twterm/event/base'
3
3
  module Twterm
4
4
  module Event
5
5
  module Notification
6
- class AbstractNotification < Twterm::Event::Base
7
- attr_reader :time
8
-
9
- def initialize(message)
10
- super(CGI.unescapeHTML(message))
6
+ # @abstract
7
+ class AbstractNotification < Event::Base
8
+ # @abstract
9
+ # @return [String] notification body
10
+ def body
11
+ raise NotImplementedError, '`body` must be implemented'
12
+ end
11
13
 
12
- @time = Time.now
14
+ # @return [String] a fallback text
15
+ def fallback
16
+ "#{title}: #{body}"
13
17
  end
14
18
 
15
- def fields
16
- {
17
- message: String
18
- }
19
+ # @abstract
20
+ # @return [String] notification title
21
+ def title
22
+ raise NotImplementedError, '`fallback` must be implemented'
19
23
  end
20
24
 
21
- def color
22
- raise NotImplementedError, 'color method must be overridden'
25
+ # @return [String, nil] notification URL
26
+ def url
27
+ nil
23
28
  end
24
29
  end
25
30
  end
@@ -0,0 +1,30 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class DirectMessage < AbstractNotification
7
+ # @param [Twterm::DirectMessage] message
8
+ # @param [Twterm::User] user
9
+ def initialize(message, user)
10
+ @message = message
11
+ @user = user
12
+ end
13
+
14
+ # @return [String] notification body
15
+ def body
16
+ message.text
17
+ end
18
+
19
+ # @return [String] notification title
20
+ def title
21
+ "@#{user.screen_name} has sent you a message"
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :message, :user
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class Like < AbstractNotification
7
+ # @param [Twterm::Status] status
8
+ # @param [Twterm::User] user
9
+ def initialize(status, user)
10
+ @status = status
11
+ @user = user
12
+ end
13
+
14
+ # @return [String] notification body
15
+ def body
16
+ status.text
17
+ end
18
+
19
+ # @return [String] notification title
20
+ def title
21
+ "@#{user.screen_name} has liked your tweet"
22
+ end
23
+
24
+ # @return [String] notification url
25
+ def url
26
+ status.url
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :status, :user
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ require 'twterm/event/notification/abstract_notification'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Notification
6
+ class Follow < AbstractNotification
7
+ # @param [Twterm::User] user
8
+ def initialize(user)
9
+ @user = user
10
+ end
11
+
12
+ # @return [String] notification body
13
+ def body
14
+ user.description
15
+ end
16
+
17
+ # @return [String] notification title
18
+ def title
19
+ "@#{user.screen_name} has followed you"
20
+ end
21
+
22
+ # @return [String] notification url
23
+ def url
24
+ user.url
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :user
30
+ end
31
+ end
32
+ end
33
+ end