draftcode-termtter 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
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,8 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Termtter::Client.add_filter do |statuses, _|
4
+ statuses.select {|s| /^(?:\s|(y\s)|(?:hara\s))+\s*(?:y|(?:hara))(?:\?|!|\.)?\s*$/ =~ s.text }
5
+ end
6
+
7
+ # yhara_filter.rb
8
+ # select Yharian post only
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ register_command(:name => :yonda,
5
+ :aliases => [:y],
6
+ :exec_proc => lambda { |arg|
7
+ public_storage[:unread_count] = 0
8
+ print "\033[2J\033[H" # FIXME
9
+ true
10
+ },
11
+ :help => ['yonda,y', 'Mark as read']
12
+ )
13
+
14
+ register_hook(:name => :yonda,
15
+ :points => [:post_exec__update_timeline],
16
+ :exec_proc => lambda { |cmd, arg, result|
17
+ public_storage[:unread_count] ||= 0
18
+ public_storage[:unread_count] += result.size
19
+ }
20
+ )
21
+ end
data/lib/termtter.rb ADDED
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ $KCODE="u" unless Object.const_defined? :Encoding
4
+
5
+ $:.unshift(File.dirname(__FILE__)) unless
6
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
7
+
8
+ require 'rubygems'
9
+ require 'json'
10
+ require 'net/https'
11
+ require 'open-uri'
12
+ require 'cgi'
13
+ require 'readline'
14
+ require 'enumerator'
15
+ require 'optparse'
16
+
17
+ require 'termtter/config'
18
+ require 'termtter/version'
19
+ require 'termtter/optparse'
20
+ require 'termtter/connection'
21
+ require 'termtter/command'
22
+ require 'termtter/hook'
23
+ require 'termtter/task'
24
+ require 'termtter/task_manager'
25
+ require 'termtter/client'
26
+ require 'termtter/api'
27
+ require 'termtter/system_extensions'
28
+
29
+ module Termtter
30
+ APP_NAME = 'termtter'
31
+
32
+ config.system.set_default :conf_dir, File.expand_path('~/.termtter')
33
+ CONF_DIR = config.system.conf_dir
34
+
35
+ config.system.set_default :conf_file, CONF_DIR + '/config'
36
+ CONF_FILE = config.system.conf_file
37
+ $:.unshift(Termtter::CONF_DIR)
38
+ end
@@ -0,0 +1,57 @@
1
+ # -*- coding: utf-8 -*-
2
+ gem 'rubytter', '>= 0.6.5'
3
+ require 'rubytter'
4
+
5
+ config.set_default(:host, 'twitter.com')
6
+ config.proxy.set_default(:port, '8080')
7
+ config.proxy.set_default(:host, nil)
8
+ config.proxy.set_default(:port, nil)
9
+ config.proxy.set_default(:user_name, nil)
10
+ config.proxy.set_default(:password, nil)
11
+ config.set_default(:enable_ssl, false)
12
+
13
+ module Termtter
14
+ module API
15
+ class << self
16
+ attr_reader :connection, :twitter
17
+ def setup
18
+ @connection = Connection.new
19
+ @twitter = create_twitter(config.user_name, config.password)
20
+ end
21
+
22
+ def restore_user
23
+ @twitter = create_twitter(config.user_name, config.password)
24
+ end
25
+
26
+ def switch_user(username = nil)
27
+ highline = create_highline
28
+ username = highline.ask('your twitter username: ') if username.nil? || username.empty?
29
+ password = highline.ask('your twitter password: ') { |q| q.echo = false }
30
+ @twitter = create_twitter(username, password)
31
+ end
32
+
33
+ def create_twitter(user_name, password)
34
+ Rubytter.new(
35
+ user_name,
36
+ password,
37
+ {
38
+ :app_name => config.app_name.empty? ? Termtter::APP_NAME : config.app_name,
39
+ :host => config.host,
40
+ :header => {
41
+ 'User-Agent' => 'Termtter http://github.com/jugyo/termtter',
42
+ 'X-Twitter-Client' => 'Termtter',
43
+ 'X-Twitter-Client-URL' => 'http://github.com/jugyo/termtter',
44
+ 'X-Twitter-Client-Version' => Termtter::VERSION
45
+ },
46
+ :enable_ssl => config.enable_ssl,
47
+ :proxy_host => config.proxy.host,
48
+ :proxy_port => config.proxy.port,
49
+ :proxy_user_name => config.proxy.user_name,
50
+ :proxy_password => config.proxy.password
51
+ }
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
57
+ # Termtter::API.connection, Termtter::API.twitter can be accessed.
@@ -0,0 +1,324 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'fileutils'
3
+ require 'logger'
4
+ require 'termcolor'
5
+
6
+ module Termtter
7
+
8
+ class CommandNotFound < StandardError; end
9
+ class CommandCanceled < StandardError; end
10
+
11
+ module Client
12
+
13
+ class << self
14
+
15
+ def init
16
+ @hooks = {}
17
+ @commands = {}
18
+ @filters = []
19
+ @since_id = nil
20
+ @task_manager = Termtter::TaskManager.new
21
+ config.set_default(:logger, nil)
22
+ config.set_default(:update_interval, 300)
23
+ config.set_default(:prompt, '> ')
24
+ config.set_default(:devel, false)
25
+ Thread.abort_on_exception = true
26
+ end
27
+
28
+ def public_storage
29
+ @public_storage ||= {}
30
+ end
31
+
32
+ def add_filter(&b)
33
+ @filters << b
34
+ end
35
+
36
+ def clear_filter
37
+ @filters.clear
38
+ end
39
+
40
+ def register_hook(arg)
41
+ hook = case arg
42
+ when Hook
43
+ arg
44
+ when Hash
45
+ Hook.new(arg)
46
+ else
47
+ raise ArgumentError, 'must be given Termtter::Hook or Hash'
48
+ end
49
+ @hooks[hook.name] = hook
50
+ end
51
+
52
+ def get_hook(name)
53
+ @hooks[name]
54
+ end
55
+
56
+ def get_hooks(point)
57
+ @hooks.values.select do |hook|
58
+ hook.match?(point)
59
+ end
60
+ end
61
+
62
+ def register_command(arg)
63
+ command = case arg
64
+ when Command
65
+ arg
66
+ when Hash
67
+ Command.new(arg)
68
+ else
69
+ raise ArgumentError, 'must be given Termtter::Command or Hash'
70
+ end
71
+ @commands[command.name] = command
72
+ end
73
+
74
+ def get_command(name)
75
+ @commands[name]
76
+ end
77
+
78
+ def get_command_completion_proc()
79
+ lambda {|input|
80
+ begin
81
+ @commands.map {|name, command| command.complement(input) }.flatten.compact
82
+ rescue => e
83
+ handle_error(e)
84
+ end
85
+ }
86
+ end
87
+
88
+ def register_macro(name, macro, options = {})
89
+ command = {
90
+ :name => name.to_sym,
91
+ :exec_proc => lambda {|arg| call_commands(macro % arg)}
92
+ }.merge(options)
93
+ register_command(command)
94
+ end
95
+
96
+ # statuses => [status, status, ...]
97
+ # status => {
98
+ # :id => status id,
99
+ # :created_at => created time,
100
+ # :user_id => user id,
101
+ # :name => user name,
102
+ # :screen_name => user screen_name,
103
+ # :source => source,
104
+ # :reply_to => reply_to status id,
105
+ # :text => status,
106
+ # :original_data => original data,
107
+ # }
108
+ def output(statuses, event)
109
+ return if statuses.nil? || statuses.empty?
110
+
111
+ statuses = statuses.sort_by{|s|s.id}
112
+ call_hooks(:pre_filter, statuses, event)
113
+ filtered = apply_filters(statuses, event)
114
+ call_hooks(:post_filter, filtered, event)
115
+ get_hooks(:output).each do |hook|
116
+ filtered_for_hook = apply_filters_for_hook(filtered, hook.name)
117
+ hook.call(filtered_for_hook, event)
118
+ end
119
+ end
120
+
121
+ def apply_filters(statuses, event)
122
+ filtered = statuses.map(&:dup)
123
+ @filters.each do |f|
124
+ filtered = f.call(filtered, event)
125
+ end
126
+ filtered
127
+ end
128
+
129
+ def apply_filters_for_hook(statuses, hook_name)
130
+ # TODO
131
+ filtered = statuses.map(&:dup)
132
+ filtered
133
+ end
134
+
135
+ # return last hook return value
136
+ def call_hooks(point, *args)
137
+ result = nil
138
+ get_hooks(point).each {|hook|
139
+ break if result == false # interrupt if hook return false
140
+ result = hook.call(*args)
141
+ }
142
+ result
143
+ end
144
+
145
+ def call_commands(text, tw = nil)
146
+ return if text.empty?
147
+
148
+ command_found = false
149
+ @commands.each do |key, command|
150
+ next unless command.match?(text)
151
+ command_found = true
152
+ command_str, command_arg = Command.split_command_line(text)
153
+
154
+ modified_arg = call_hooks(
155
+ "modify_arg_for_#{command.name.to_s}",
156
+ command_str,
157
+ command_arg) || command_arg || ''
158
+
159
+ @task_manager.invoke_and_wait do
160
+ begin
161
+ call_hooks("pre_exec_#{command.name.to_s}", command, modified_arg)
162
+ # exec command
163
+ result = command.call(command_str, modified_arg, text)
164
+ if result
165
+ call_hooks("post_exec_#{command.name.to_s}", command_str, modified_arg, result)
166
+ end
167
+ rescue CommandCanceled
168
+ end
169
+ end
170
+ end
171
+
172
+ raise CommandNotFound, text unless command_found
173
+ end
174
+
175
+ def pause
176
+ @task_manager.pause
177
+ end
178
+
179
+ def resume
180
+ @task_manager.resume
181
+ end
182
+
183
+ def add_task(*arg, &block)
184
+ @task_manager.add_task(*arg, &block)
185
+ end
186
+
187
+ def exit
188
+ puts 'finalizing...'
189
+
190
+ call_hooks(:exit)
191
+ @task_manager.kill
192
+ end
193
+
194
+ def load_default_plugins
195
+ plugin 'standard_plugins'
196
+ plugin 'stdout'
197
+ end
198
+
199
+ def load_config
200
+ legacy_config_support() if File.exist? Termtter::CONF_DIR
201
+ unless File.exist?(Termtter::CONF_FILE)
202
+ require 'termtter/config_setup'
203
+ ConfigSetup.run
204
+ end
205
+ load Termtter::CONF_FILE
206
+ end
207
+
208
+ def legacy_config_support
209
+ case File.ftype(File.expand_path('~/.termtter'))
210
+ when 'directory'
211
+ # nop
212
+ when 'file'
213
+ move_legacy_config_file
214
+ end
215
+ end
216
+
217
+ def move_legacy_config_file
218
+ FileUtils.mv(
219
+ Termtter::CONF_DIR,
220
+ File.expand_path('~/.termtter___'))
221
+ Dir.mkdir(Termtter::CONF_DIR)
222
+ FileUtils.mv(
223
+ File.expand_path('~/.termtter___'),
224
+ Termtter::CONF_FILE)
225
+ end
226
+
227
+ def post_config_load()
228
+ if config.devel
229
+ plugin 'devel'
230
+ end
231
+ end
232
+
233
+
234
+ # TODO: Make pluggable
235
+ def setup_update_timeline_task()
236
+ register_command(
237
+ :name => :_update_timeline,
238
+ :exec_proc => lambda {|arg|
239
+ begin
240
+ args = @since_id ? [{:since_id => @since_id}] : []
241
+ statuses = Termtter::API.twitter.friends_timeline(*args)
242
+ unless statuses.empty?
243
+ @since_id = statuses[0].id
244
+ output(statuses, :update_friends_timeline)
245
+ end
246
+ rescue OpenURI::HTTPError => e
247
+ if e.message == '401 Unauthorized'
248
+ puts 'Could not login'
249
+ puts 'plese check your account settings'
250
+ exit!
251
+ end
252
+ rescue => e
253
+ handle_error(e)
254
+ end
255
+ }
256
+ )
257
+
258
+ add_task(:name => :update_timeline, :interval => config.update_interval, :after => config.update_interval) do
259
+ call_commands('_update_timeline')
260
+ end
261
+ end
262
+
263
+ def logger
264
+ @logger
265
+ end
266
+
267
+ def setup_logger
268
+ @logger = config.logger || default_logger
269
+ end
270
+
271
+ def default_logger
272
+ logger = Logger.new(STDOUT)
273
+ logger.formatter = lambda { |severity, time, progname, message|
274
+ color =
275
+ case severity
276
+ when /^DEBUG/
277
+ 'blue'
278
+ when /^INFO/
279
+ 'cyan'
280
+ when /^WARN/
281
+ 'magenta'
282
+ when /^ERROR/
283
+ 'red'
284
+ when /^FATAL/
285
+ 'on_red'
286
+ else
287
+ 'white'
288
+ end
289
+ TermColor.parse("<#{color}>" + TermColor.escape("[#{severity}] #{message}\n") + "</#{color}>")
290
+ }
291
+ logger
292
+ end
293
+
294
+ def run
295
+ load_default_plugins()
296
+ load_config()
297
+ Termtter::API.setup()
298
+ setup_logger()
299
+ post_config_load()
300
+
301
+ call_hooks(:initialize)
302
+ setup_update_timeline_task()
303
+ call_commands('_update_timeline')
304
+ @task_manager.run()
305
+ call_hooks(:before_task_thread_run)
306
+ end
307
+
308
+ def handle_error(e)
309
+ if logger
310
+ logger.error("#{e.class.to_s}: #{e.message}")
311
+ logger.error(e.backtrace.join("\n")) if config.devel
312
+ else
313
+ raise e
314
+ end
315
+ get_hooks(:on_error).each {|hook| hook.call(e) }
316
+ rescue Exception => e
317
+ puts "Error: #{e}"
318
+ puts e.backtrace.join("\n")
319
+ end
320
+ end
321
+ end
322
+ end
323
+
324
+ Termtter::Client.init