draftcode-termtter 1.0.8

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.
Files changed (118) hide show
  1. data/History.txt +4 -0
  2. data/README.rdoc +100 -0
  3. data/Rakefile +55 -0
  4. data/bin/kill_termtter +22 -0
  5. data/bin/termtter +6 -0
  6. data/lib/plugins/addspace.rb +27 -0
  7. data/lib/plugins/april_fool.rb +15 -0
  8. data/lib/plugins/bomb.rb +39 -0
  9. data/lib/plugins/clear.rb +14 -0
  10. data/lib/plugins/command_plus.rb +47 -0
  11. data/lib/plugins/confirm.rb +33 -0
  12. data/lib/plugins/cool.rb +10 -0
  13. data/lib/plugins/countter.rb +23 -0
  14. data/lib/plugins/devel.rb +18 -0
  15. data/lib/plugins/direct_messages.rb +36 -0
  16. data/lib/plugins/en2ja.rb +11 -0
  17. data/lib/plugins/english.rb +25 -0
  18. data/lib/plugins/erb.rb +17 -0
  19. data/lib/plugins/exec.rb +17 -0
  20. data/lib/plugins/exec_and_update.rb +14 -0
  21. data/lib/plugins/expand-tinyurl.rb +34 -0
  22. data/lib/plugins/fib.rb +28 -0
  23. data/lib/plugins/fib_filter.rb +14 -0
  24. data/lib/plugins/filter.rb +69 -0
  25. data/lib/plugins/graduatter.rb +8 -0
  26. data/lib/plugins/grass.rb +27 -0
  27. data/lib/plugins/group.rb +64 -0
  28. data/lib/plugins/growl.rb +52 -0
  29. data/lib/plugins/growl2.rb +143 -0
  30. data/lib/plugins/hatebu.rb +59 -0
  31. data/lib/plugins/hatebu_and_update.rb +58 -0
  32. data/lib/plugins/history.rb +93 -0
  33. data/lib/plugins/ignore.rb +19 -0
  34. data/lib/plugins/keyword.rb +18 -0
  35. data/lib/plugins/l2.rb +25 -0
  36. data/lib/plugins/log.rb +73 -0
  37. data/lib/plugins/me.rb +10 -0
  38. data/lib/plugins/modify_arg_hook_sample.rb +7 -0
  39. data/lib/plugins/msagent.rb +38 -0
  40. data/lib/plugins/multi_reply.rb +27 -0
  41. data/lib/plugins/notify-send.rb +22 -0
  42. data/lib/plugins/notify-send2.rb +52 -0
  43. data/lib/plugins/notify-send3.rb +45 -0
  44. data/lib/plugins/open_url.rb +59 -0
  45. data/lib/plugins/otsune.rb +21 -0
  46. data/lib/plugins/outputz.rb +33 -0
  47. data/lib/plugins/pause.rb +3 -0
  48. data/lib/plugins/post_exec_hook_sample.rb +9 -0
  49. data/lib/plugins/pre_exec_hook_sample.rb +9 -0
  50. data/lib/plugins/primes.rb +30 -0
  51. data/lib/plugins/quicklook.rb +41 -0
  52. data/lib/plugins/random.rb +23 -0
  53. data/lib/plugins/reblog.rb +40 -0
  54. data/lib/plugins/reload.rb +3 -0
  55. data/lib/plugins/reply.rb +8 -0
  56. data/lib/plugins/retweet.rb +46 -0
  57. data/lib/plugins/reverse.rb +13 -0
  58. data/lib/plugins/say.rb +26 -0
  59. data/lib/plugins/scrape.rb +41 -0
  60. data/lib/plugins/screen-notify.rb +20 -0
  61. data/lib/plugins/screen.rb +24 -0
  62. data/lib/plugins/shell.rb +14 -0
  63. data/lib/plugins/sl.rb +48 -0
  64. data/lib/plugins/spam.rb +16 -0
  65. data/lib/plugins/standard_plugins.rb +525 -0
  66. data/lib/plugins/stdout.rb +220 -0
  67. data/lib/plugins/storage.rb +55 -0
  68. data/lib/plugins/storage/DB.rb +37 -0
  69. data/lib/plugins/storage/status.rb +83 -0
  70. data/lib/plugins/storage/status_mook.rb +30 -0
  71. data/lib/plugins/switch_user.rb +22 -0
  72. data/lib/plugins/system_status.rb +33 -0
  73. data/lib/plugins/timer.rb +18 -0
  74. data/lib/plugins/tinyurl.rb +20 -0
  75. data/lib/plugins/translation.rb +38 -0
  76. data/lib/plugins/typable_id.rb +94 -0
  77. data/lib/plugins/update_editor.rb +53 -0
  78. data/lib/plugins/uri-open.rb +66 -0
  79. data/lib/plugins/wassr_post.rb +22 -0
  80. data/lib/plugins/yhara.rb +148 -0
  81. data/lib/plugins/yhara_filter.rb +8 -0
  82. data/lib/plugins/yonda.rb +21 -0
  83. data/lib/termtter.rb +38 -0
  84. data/lib/termtter/api.rb +57 -0
  85. data/lib/termtter/client.rb +324 -0
  86. data/lib/termtter/command.rb +80 -0
  87. data/lib/termtter/config.rb +68 -0
  88. data/lib/termtter/config_setup.rb +38 -0
  89. data/lib/termtter/connection.rb +41 -0
  90. data/lib/termtter/hook.rb +31 -0
  91. data/lib/termtter/optparse.rb +14 -0
  92. data/lib/termtter/system_extensions.rb +115 -0
  93. data/lib/termtter/task.rb +17 -0
  94. data/lib/termtter/task_manager.rb +116 -0
  95. data/lib/termtter/version.rb +4 -0
  96. data/spec/plugins/cool_spec.rb +10 -0
  97. data/spec/plugins/english_spec.rb +19 -0
  98. data/spec/plugins/fib_spec.rb +15 -0
  99. data/spec/plugins/filter_spec.rb +18 -0
  100. data/spec/plugins/pause_spec.rb +8 -0
  101. data/spec/plugins/primes_spec.rb +15 -0
  102. data/spec/plugins/shell_spec.rb +10 -0
  103. data/spec/plugins/sl_spec.rb +8 -0
  104. data/spec/plugins/spam_spec.rb +4 -0
  105. data/spec/plugins/standard_plugins_spec.rb +23 -0
  106. data/spec/plugins/storage/DB_spec.rb +12 -0
  107. data/spec/plugins/storage/status_spec.rb +24 -0
  108. data/spec/spec_helper.rb +7 -0
  109. data/spec/termtter/client_spec.rb +255 -0
  110. data/spec/termtter/command_spec.rb +107 -0
  111. data/spec/termtter/config_spec.rb +111 -0
  112. data/spec/termtter/hook_spec.rb +78 -0
  113. data/spec/termtter/task_manager_spec.rb +78 -0
  114. data/spec/termtter/task_spec.rb +22 -0
  115. data/spec/termtter_spec.rb +29 -0
  116. data/test/friends_timeline.json +5 -0
  117. data/test/search.json +8 -0
  118. metadata +211 -0
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ add_filter do |statuses, _|
5
+ statuses.map do |s|
6
+ s.text = s.text.split(//).reverse.to_s
7
+ s
8
+ end
9
+ end
10
+ end
11
+
12
+ # filter-reverse.rb
13
+ # reverse texts
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ raise 'say.rb runs only in OSX Leopard' if /darwin9/ !~ RUBY_PLATFORM
4
+
5
+ # say :: String -> String -> IO ()
6
+ def say(who, what)
7
+ voices = %w(Alex Alex Bruce Fred Ralph Agnes Kathy Vicki)
8
+ voice = voices[who.hash % voices.size]
9
+ system 'say', '-v', voice, what
10
+ end
11
+
12
+ module Termtter::Client
13
+ register_hook(
14
+ :name => :say,
15
+ :points => [:output],
16
+ :exec_proc => lambda {|statuses, event|
17
+ statuses.reverse.each do |s|
18
+ text_without_uri = s[:text].gsub(%r|https?://[^\s]+|, 'U.R.I.')
19
+ say s[:screen_name], text_without_uri
20
+ end
21
+ }
22
+ )
23
+ end
24
+
25
+ # KNOWN BUG:
26
+ # * exit or <C-c> doen't work quickly.
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+
5
+ def self.scrape_members(members)
6
+ statuses = []
7
+ members.each_with_index do |member, index|
8
+ puts "member #{index+1}/#{members.size} #{member}"
9
+ statuses += Termtter::API.twitter.user_timeline(member)
10
+ end
11
+ statuses
12
+ end
13
+
14
+ def self.scrape_group(group)
15
+ members = config.plugins.group.groups[group] || []
16
+ scrape_members(members)
17
+ end
18
+
19
+ register_command(
20
+ :name => :scrape_group,
21
+ :exec_proc => lambda{ |args|
22
+ groups = args.split(' ').map{|g| g.to_sym}
23
+ if groups.include? :all
24
+ groups = config.plugins.group.groups.keys
25
+ puts "get all groups..."
26
+ end
27
+ members = []
28
+ groups.each do |group|
29
+ members += config.plugins.group.groups[group]
30
+ end
31
+ statuses = scrape_members(members.uniq.compact.sort)
32
+ output(statuses_to_hash(statuses), :pre_filter)
33
+ },
34
+ :completion_proc => lambda {|cmd, args|
35
+ arg = args.split(' ').last
36
+ prefix = args.split(' ')[0..-2].join(' ')
37
+ find_group_candidates arg, "#{cmd} #{prefix} %s"
38
+ },
39
+ :help => ['scrape_group GROUPNAME(S)', 'Get the group timeline']
40
+ )
41
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ config.screen_notify.set_default(:format, "[termtter] %s")
4
+
5
+ module Termtter::Client
6
+ register_hook(
7
+ :name => :screen_notify,
8
+ :points => [:output],
9
+ :exec_proc => lambda{|statuses, event|
10
+ return unless event = :update_friends_timeline
11
+ Thread.new(statuses) do |ss|
12
+ ss.each do |s|
13
+ msg = config.screen_notify.format % s.user.screen_name
14
+ system 'screen', '-X', 'eval', "bell_msg '#{msg}'", 'bell'
15
+ sleep 1
16
+ end
17
+ end
18
+ }
19
+ )
20
+ end
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter
4
+ module Plugin
5
+ module Screen
6
+ def self.set_title(title)
7
+ print "\033k#{title}\033\\\n"
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ # Add below to your ~/.termtter
14
+ #
15
+ # require 'plugins/yonda'
16
+ # require 'plugins/screen'
17
+ # module Termtter::Client
18
+ # register_hook(:name => :screen,
19
+ # :points => [:post_exec__update_timeline, :plugin_yonda_yonda, :post_exec_yonda],
20
+ # :exec_proc => lambda { |cmd, arg, result|
21
+ # Termtter::Plugin::Screen::set_title("termtter(#{public_storage[:unread_count]})")
22
+ # }
23
+ # )
24
+ # end
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ register_command :name => :shell, :aliases => [:sh],
5
+ :help => ['shell,sh', 'Start your shell'],
6
+ :exec_proc => lambda {|args|
7
+ begin
8
+ pause
9
+ system ENV['SHELL'] || ENV['COMSPEC']
10
+ ensure
11
+ resume
12
+ end
13
+ }
14
+ end
data/lib/plugins/sl.rb ADDED
@@ -0,0 +1,48 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter
4
+
5
+ module Client
6
+
7
+ public_storage[:current] = ''
8
+ public_storage[:orig_prompt] = config.prompt
9
+ config.prompt = "~/ #{public_storage[:orig_prompt]}"
10
+
11
+ register_command(
12
+ :name => :sl, :aliases => [],
13
+ :exec_proc => lambda {|arg| system("sl") },
14
+ :help => ['sl', 'The train pass in front of your screen']
15
+ )
16
+
17
+ register_command(
18
+ :name => :pwd, :aliases => [],
19
+ :exec_proc => lambda {|arg| public_storage[:current] },
20
+ :help => ['pwd', 'Show current direcroty']
21
+ )
22
+
23
+ register_command(
24
+ :name => :ls, :aliases => [],
25
+ :exec_proc => lambda {|arg|
26
+ call_commands("list #{arg.empty? ? public_storage[:current] : arg}")
27
+ },
28
+ :completion_proc => lambda {|cmd, args|
29
+ find_user_candidates args, "#{cmd} %s"
30
+ },
31
+ :help => ['ls', 'Show list in current directory']
32
+ )
33
+
34
+ register_command(
35
+ :name => :cd, :aliases => [],
36
+ :exec_proc => lambda {|arg|
37
+ public_storage[:current] =
38
+ (arg.nil? || /\~/ =~ arg) ? '' : arg
39
+ config.prompt = "~/#{public_storage[:current]} #{public_storage[:orig_prompt]}"
40
+ },
41
+ :completion_proc => lambda {|cmd, args|
42
+ find_user_candidates args, "#{cmd} %s"
43
+ },
44
+ :help => ['cd USER', 'Change current directory']
45
+ )
46
+ end
47
+ end
48
+
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ message = '*super spam time*'
4
+ Termtter::API.twitter.update(message)
5
+ puts "=> #{message}"
6
+
7
+ Termtter::Client.register_hook(
8
+ :name => :span,
9
+ :point => /^pre_exec/,
10
+ :exec => lambda{|*arg|
11
+ text = arg.join(' ')
12
+ Termtter::API.twitter.update(text)
13
+ puts "=> #{text}"
14
+ raise Termtter::CommandCanceled
15
+ }
16
+ )
@@ -0,0 +1,525 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'erb'
4
+ require 'set'
5
+
6
+ config.plugins.standard.set_default(
7
+ :limit_format,
8
+ '<<%=remaining_color%>><%=limit.remaining_hits%></<%=remaining_color%>>/<%=limit.hourly_limit%> until <%=limit.reset_time%> (<%=remaining_time%> remaining)')
9
+
10
+ module Termtter::Client
11
+
12
+ register_command(
13
+ :name => :update, :aliases => [:u],
14
+ :exec_proc => lambda {|arg|
15
+ unless arg.empty?
16
+ Termtter::API.twitter.update(arg)
17
+ puts "=> #{arg}"
18
+ end
19
+ },
20
+ :completion_proc => lambda {|cmd, args|
21
+ if /(.*)@([^\s]*)$/ =~ args
22
+ find_user_candidates $2, "#{cmd} #{$1}@%s"
23
+ end
24
+ },
25
+ :help => ["update,u TEXT", "Post a new message"]
26
+ )
27
+
28
+ direct_message_struct = Struct.new(:id, :text, :user, :created_at)
29
+ direct_message_struct.class_eval do
30
+ def method_missing(*args, &block)
31
+ nil
32
+ end
33
+ end
34
+ register_command(
35
+ :name => :direct, :aliases => [:d],
36
+ :exec_proc => lambda {|arg|
37
+ case arg
38
+ when /^([^\s]+)\s+(.*)\s*$/
39
+ user, text = $1, $2
40
+ Termtter::API.twitter.direct_message(user, text)
41
+ puts "=> to:#{user} message:#{text}"
42
+ when 'list'
43
+ output(
44
+ Termtter::API.twitter.direct_messages.map { |d|
45
+ direct_message_struct.new(d.id, "#{d.text} => #{d.recipient_screen_name}", d.sender, d.created_at)
46
+ },
47
+ :direct_messages
48
+ )
49
+ when 'sent_list'
50
+ output(
51
+ Termtter::API.twitter.sent_direct_messages.map { |d|
52
+ direct_message_struct.new(d.id, "#{d.text} => #{d.recipient_screen_name}", d.sender, d.created_at)
53
+ },
54
+ :direct_messages
55
+ )
56
+ end
57
+ },
58
+ :completion_proc => lambda {|cmd, arg|
59
+ find_user_candidates(arg, "#{cmd} %s") +
60
+ ["list", "sent_list"].grep(/^#{Regexp.quote(arg)}/).map { |i| "#{cmd} #{i}" }
61
+ },
62
+ :help => [
63
+ ["direct,d USERNAME TEXT", "Send direct message"],
64
+ ["direct,d list", 'List direct messages'],
65
+ ["direct,d sent_list", 'List sent direct messages']
66
+ ]
67
+ )
68
+
69
+ register_command(
70
+ :name => :profile, :aliases => [:p],
71
+ :exec_proc => lambda {|arg|
72
+ user = Termtter::API.twitter.user(arg.strip)
73
+ attrs = %w[ name screen_name url description profile_image_url location protected following
74
+ friends_count followers_count statuses_count favourites_count
75
+ id time_zone created_at utc_offset notifications
76
+ ]
77
+ label_width = attrs.map(&:size).max
78
+ attrs.each do |attr|
79
+ value = user.__send__(attr.to_sym)
80
+ puts "#{attr.gsub('_', ' ').rjust(label_width)}: #{value}"
81
+ end
82
+ },
83
+ :completion_proc => lambda {|cmd, arg|
84
+ find_user_candidates arg, "#{cmd} %s"
85
+ },
86
+ :help => ["profile,p USERNAME", "Show user's profile"]
87
+ )
88
+
89
+ register_command(
90
+ :name => :followers,
91
+ :exec_proc => lambda {|arg|
92
+ user_name = arg.strip
93
+ user_name = config.user_name if user_name.empty?
94
+
95
+ followers = []
96
+ page = 0
97
+ begin
98
+ followers += tmp = Termtter::API.twitter.followers(user_name, :page => page+=1)
99
+ end until tmp.empty?
100
+ Termtter::Client.public_storage[:followers] = followers
101
+ public_storage[:users] += followers.map(&:screen_name)
102
+ puts followers.map(&:screen_name).join(' ')
103
+ },
104
+ :completion_proc => lambda {|cmd, arg|
105
+ find_user_candidates arg, "#{cmd} %s"
106
+ },
107
+ :help => ["followers", "Show followers"]
108
+ )
109
+
110
+ register_command(
111
+ :name => :list, :aliases => [:l],
112
+ :exec_proc => lambda {|arg|
113
+ if arg.empty?
114
+ event = :list_friends_timeline
115
+ statuses = Termtter::API.twitter.friends_timeline
116
+ else
117
+ event = :list_user_timeline
118
+ statuses = Termtter::API.twitter.user_timeline(arg)
119
+ end
120
+ output(statuses, event)
121
+ },
122
+ :completion_proc => lambda {|cmd, arg|
123
+ find_user_candidates arg, "#{cmd} %s"
124
+ },
125
+ :help => ["list,l [USERNAME]", "List the posts"]
126
+ )
127
+
128
+ public_storage[:search_keywords] = Set.new
129
+ register_command(
130
+ :name => :search, :aliases => [:s],
131
+ :exec_proc => lambda {|arg|
132
+ statuses = Termtter::API.twitter.search(arg)
133
+ public_storage[:search_keywords] << arg
134
+ output(statuses, :search)
135
+ },
136
+ :completion_proc => lambda {|cmd, arg|
137
+ public_storage[:search_keywords].grep(/#{Regexp.quote(arg)}/).map { |i| "#{cmd} #{i}" }
138
+ },
139
+ :help => ["search,s TEXT", "Search for Twitter"]
140
+ )
141
+
142
+ register_command(
143
+ :name => :replies, :aliases => [:r],
144
+ :exec_proc => lambda {|arg|
145
+ output(Termtter::API.twitter.replies, :replies)
146
+ },
147
+ :help => ["replies,r", "List the most recent @replies for the authenticating user"]
148
+ )
149
+
150
+ register_command(
151
+ :name => :show,
152
+ :exec_proc => lambda {|arg|
153
+ id = arg.gsub(/.*:\s*/, '')
154
+ output([Termtter::API.twitter.show(id)], :show)
155
+ },
156
+ :completion_proc => lambda {|cmd, arg|
157
+ case arg
158
+ when /(\w+):\s*(\d+)\s*$/
159
+ find_status_ids($2).map{|id| "#{cmd} #{$1}: #{id}"}
160
+ else
161
+ users = find_users(arg)
162
+ unless users.empty?
163
+ users.map {|user| "#{cmd} #{user}:"}
164
+ else
165
+ find_status_ids(arg).map {|id| "#{cmd} #{id}"}
166
+ end
167
+ end
168
+ },
169
+ :help => ["show ID", "Show a single status"]
170
+ )
171
+
172
+ register_command(
173
+ :name => :shows,
174
+ :exec_proc => lambda {|arg|
175
+ id = arg.gsub(/.*:\s*/, '')
176
+ # TODO: Implement
177
+ #output([Termtter::API.twitter.show(id)], :show)
178
+ puts "Not implemented yet."
179
+ },
180
+ :completion_proc => get_command(:show).completion_proc
181
+ )
182
+
183
+ register_command(
184
+ :name => :follow, :aliases => [],
185
+ :exec_proc => lambda {|args|
186
+ args.split(' ').each do |arg|
187
+ if /^(\w+)/ =~ arg
188
+ res = Termtter::API::twitter.follow($1.strip)
189
+ end
190
+ end
191
+ },
192
+ :completion_proc => lambda {|cmd, args|
193
+ find_user_candidates args, "#{cmd} %s"
194
+ },
195
+ :help => ['follow USER', 'Follow user']
196
+ )
197
+
198
+ register_command(
199
+ :name => :leave, :aliases => [],
200
+ :exec_proc => lambda {|args|
201
+ args.split(' ').each do |arg|
202
+ if /^(\w+)/ =~ arg
203
+ res = Termtter::API::twitter.leave($1.strip)
204
+ end
205
+ end
206
+ },
207
+ :completion_proc => lambda {|cmd, args|
208
+ find_user_candidates args, "#{cmd} %s"
209
+ },
210
+ :help => ['leave USER', 'Leave user']
211
+ )
212
+
213
+ register_command(
214
+ :name => :favorite, :aliases => [:fav],
215
+ :exec_proc => lambda {|arg|
216
+ id = 0
217
+ case arg
218
+ when /^\d+/
219
+ id = arg.to_i
220
+ when /^@([A-Za-z0-9_]+)/
221
+ user = $1
222
+ statuses = Termtter::API.twitter.user_timeline(user)
223
+ return if statuses.empty?
224
+ id = statuses[0].id
225
+ when /^\/(.*)$/
226
+ word = $1
227
+ raise "Not implemented yet."
228
+ else
229
+ return
230
+ end
231
+
232
+ r = Termtter::API.twitter.favorite id
233
+ puts "Favorited status ##{r.id} on user @#{r.user.screen_name} #{r.text}"
234
+ },
235
+ :completion_proc => lambda {|cmd, arg|
236
+ case arg
237
+ when /@(.*)/
238
+ find_user_candidates $1, "#{cmd} @%s"
239
+ when /(\d+)/
240
+ find_status_ids(arg).map{|id| "#{cmd} #{id}"}
241
+ else
242
+ %w(favorite).grep(/^#{Regexp.quote arg}/)
243
+ end
244
+ },
245
+ :help => ['favorite,fav (ID|@USER|/WORD)', 'Favorite a status']
246
+ )
247
+
248
+ def self.show_settings(conf, level = 0)
249
+ conf.__values__.each do |k, v|
250
+ if v.instance_of? Termtter::Config
251
+ puts "#{k}:"
252
+ show_settings v, level + 1
253
+ else
254
+ print ' ' * level
255
+ puts "#{k} = #{v.nil? ? 'nil' : v.inspect}"
256
+ end
257
+ end
258
+ end
259
+
260
+ register_command(
261
+ :name => :settings, :aliases => [:set],
262
+ :exec_proc => lambda {|_|
263
+ show_settings config
264
+ },
265
+ :help => ['settings,set', 'Show your settings']
266
+ )
267
+
268
+ # TODO: Change colors when remaining_hits is low.
269
+ # TODO: Simmulate remaining_hits.
270
+ register_command(
271
+ :name => :limit, :aliases => [:lm],
272
+ :exec_proc => lambda {|arg|
273
+ limit = Termtter::API.twitter.limit_status
274
+ remaining_time = "%dmin %dsec" % (Time.parse(limit.reset_time) - Time.now).divmod(60)
275
+ remaining_color =
276
+ case limit.remaining_hits / limit.hourly_limit.to_f
277
+ when 0.2..0.4 then :yellow
278
+ when 0..0.2 then :red
279
+ else :green
280
+ end
281
+ erbed_text = ERB.new(config.plugins.standard.limit_format).result(binding)
282
+ puts TermColor.parse(erbed_text)
283
+ },
284
+ :help => ["limit,lm", "Show the API limit status"]
285
+ )
286
+
287
+ register_command(
288
+ :name => :pause,
289
+ :exec_proc => lambda {|arg| pause},
290
+ :help => ["pause", "Pause updating"]
291
+ )
292
+
293
+ register_command(
294
+ :name => :resume,
295
+ :exec_proc => lambda {|arg| resume},
296
+ :help => ["resume", "Resume updating"]
297
+ )
298
+
299
+ register_command(
300
+ :name => :exit, :aliases => [:e, :q, :quit],
301
+ :exec_proc => lambda {|arg| exit},
302
+ :help => ['exit,e', 'Exit']
303
+ )
304
+
305
+ register_command(
306
+ :name => :help, :aliases => [:h],
307
+ :exec_proc => lambda {|arg|
308
+ helps = []
309
+ @commands.map do |name, command|
310
+ next unless command.help
311
+ case command.help[0]
312
+ when String
313
+ helps << command.help
314
+ when Array
315
+ helps += command.help
316
+ end
317
+ end
318
+ helps.compact!
319
+ puts formatted_help(helps)
320
+ },
321
+ :help => ["help,h", "Print this help message"]
322
+ )
323
+
324
+ def self.formatted_help(helps)
325
+ helps = helps.sort_by {|help| help[0] }
326
+ width = helps.map {|n, _| n.size }.max
327
+ space = 3
328
+ helps.map {|name, desc|
329
+ name.to_s.ljust(width + space) + desc.to_s
330
+ }.join("\n")
331
+ end
332
+
333
+ # completion for standard commands
334
+
335
+ public_storage[:users] ||= Set.new
336
+ public_storage[:status_ids] ||= Set.new
337
+ public_storage[:last_status_id] ||= Hash.new
338
+
339
+ register_hook(
340
+ :name => :for_completion,
341
+ :points => [:pre_filter],
342
+ :exec_proc => lambda {|statuses, event|
343
+ statuses.each do |s|
344
+ public_storage[:users].add(s.user.screen_name)
345
+ public_storage[:users] += s.text.scan(/@([a-zA-Z_0-9]*)/).flatten
346
+ public_storage[:status_ids].add(s.id)
347
+ public_storage[:status_ids].add(s.in_reply_to_status_id) if s.in_reply_to_status_id
348
+ public_storage[:last_status_id].store(s.user.screen_name, s.id)
349
+ end
350
+ }
351
+ )
352
+
353
+ public_storage[:plugins] = (Dir["#{File.dirname(__FILE__)}/*.rb"] + Dir["#{Termtter::CONF_DIR}/plugins/*.rb"]).map do |f|
354
+ f.match(%r|([^/]+).rb$|)[1]
355
+ end
356
+
357
+ register_command(
358
+ :name => :plugin,
359
+ :exec_proc => lambda {|arg|
360
+ if arg.empty?
361
+ puts 'Should specify plugin name.'
362
+ return
363
+ end
364
+ begin
365
+ result = plugin arg
366
+ rescue LoadError
367
+ ensure
368
+ puts "=> #{result.inspect}"
369
+ end
370
+ },
371
+ :completion_proc => lambda {|cmd, args|
372
+ find_user_candidates args, "#{cmd} %s"
373
+ unless args.empty?
374
+ find_plugin_candidates args, "#{cmd} %s"
375
+ else
376
+ public_storage[:plugins].sort
377
+ end
378
+ },
379
+ :help => ['plugin FILE', 'Load a plugin']
380
+ )
381
+
382
+ register_command(
383
+ :name => :plugins,
384
+ :exec_proc => lambda {|arg|
385
+ puts public_storage[:plugins].sort.join("\n")
386
+ },
387
+ :help => ['plugins', 'Show list of plugins']
388
+ )
389
+
390
+ register_command(
391
+ :name => :reply,
392
+ :aliases => [:re],
393
+ :exec_proc => lambda {|arg|
394
+ case arg
395
+ when /^\s*(?:list|ls)\s*(?:\s+(\w+))?\s*$/
396
+ public_storage[:log4re] = if $1
397
+ public_storage[:log].
398
+ select{|l| l.user.screen_name == $1}.
399
+ sort {|a,b| a.id <=> b.id}
400
+ else
401
+ public_storage[:log].sort {|a,b| a.id <=> b.id}
402
+ end
403
+ public_storage[:log4re].each_with_index do |s, i|
404
+ puts "#{i}: #{s.user.screen_name}: #{s.text}"
405
+ end
406
+ when /^\s*(?:up(?:date)?)\s+(\d+)\s+(.+)$/
407
+ id = public_storage[:log4re][$1.to_i].id
408
+ text = $2
409
+ user = public_storage[:log4re][$1.to_i].user
410
+ update_with_user_and_id(text, user.screen_name, id) if user
411
+ public_storage.delete :log4re
412
+ when /^\s*(\d+)\s+(.+)$/
413
+ id, text = $1, $2
414
+ user = public_storage[:log].select {|l| l.id == id.to_i }.first.user
415
+ update_with_user_and_id(text, user.screen_name, id) if user
416
+ when /^\s*@(\w+)/
417
+ in_reply_to_status_id = Termtter::API.twitter.user($1).status.id rescue nil
418
+ params = in_reply_to_status_id ? {:in_reply_to_status_id => in_reply_to_status_id} : {}
419
+ Termtter::API.twitter.update(arg, params)
420
+ puts "=> #{arg}"
421
+ end
422
+ },
423
+ :completion_proc => lambda {|cmd, arg|
424
+ case arg
425
+ when /(.*)@([^\s]*)$/
426
+ find_user_candidates $2, "#{cmd} #{$1}@%s"
427
+ when /(\d+)/
428
+ find_status_ids(arg).map{|id| "#{cmd} #{id}"}
429
+ end
430
+ },
431
+ :help => ["reply,re @USERNAME or STATUS_ID", "Send a reply"]
432
+ )
433
+
434
+ register_command(
435
+ :name => :redo,
436
+ :aliases => [:"."],
437
+ :exec_proc => lambda {|arg|
438
+ break if Readline::HISTORY.length < 2
439
+ i = Readline::HISTORY.length - 2
440
+ input = ""
441
+ begin
442
+ input = Readline::HISTORY[i]
443
+ i -= 1
444
+ return if i <= 0
445
+ end while input == "redo" or input == "."
446
+ begin
447
+ Termtter::Client.call_commands(input)
448
+ rescue CommandNotFound => e
449
+ warn "Unknown command \"#{e}\""
450
+ warn 'Enter "help" for instructions'
451
+ rescue => e
452
+ handle_error e
453
+ end
454
+ },
455
+ :help => ["redo,.", "Execute previous command"]
456
+ )
457
+
458
+ def self.update_with_user_and_id(text, username, id)
459
+ text = ERB.new("@#{username} #{text}").result(binding).gsub(/\n/, ' ')
460
+ result = Termtter::API.twitter.update(text, {'in_reply_to_status_id' => id})
461
+ puts "=> #{text}"
462
+ result
463
+ end
464
+
465
+ =begin
466
+ = Termtter reply command
467
+ == Usage
468
+ === list
469
+ * ステータスリストを連番と一緒に出す。
470
+ > reply [list|ls]
471
+ 0: foo: foo's message
472
+ 1: bar: bar's message
473
+ ..
474
+
475
+ * ユーザ指定してリスト作成。
476
+ > reply [list|ls] foo
477
+ 0: foo: foo's message0
478
+ 1: foo: foo's message1
479
+
480
+ === reply
481
+ メッセージ送信の際、@usernameが自動的に付与される。
482
+
483
+ * status_idを自分で入力してreply送信
484
+ > reply 1234567890 message to status_id
485
+ => @foo message to status_id (reply to 1234567890)
486
+
487
+ * reply listコマンドで出したステータス番号に対してreply送信
488
+ > reply up 0 message to status no
489
+ => @foo message to status_no
490
+
491
+ * 対象ユーザの最後の発言に対してreply
492
+ > reply @foo message to foo
493
+ => @foo message to foo
494
+
495
+ == Todo
496
+ * 英語で説明 => ヘルプを設定する
497
+ * リファクタ
498
+ * 補完
499
+ * 確認画面を出したい
500
+ =end
501
+
502
+ def self.find_plugin_candidates(a, b)
503
+ public_storage[:plugins].
504
+ grep(/^#{Regexp.quote a}/i).
505
+ map {|u| b % u }
506
+ end
507
+
508
+ def self.find_status_ids(text)
509
+ public_storage[:status_ids].select {|id| /#{Regexp.quote(text)}/ =~ id.to_s}
510
+ end
511
+
512
+ def self.find_users(text)
513
+ public_storage[:users].select {|user| /^#{Regexp.quote(text)}/ =~ user}
514
+ end
515
+
516
+ def self.find_user_candidates(a, b)
517
+ users =
518
+ if a.nil? || a.empty?
519
+ public_storage[:users].to_a
520
+ else
521
+ public_storage[:users].grep(/^#{Regexp.quote a}/i)
522
+ end
523
+ users.map {|u| b % u }
524
+ end
525
+ end