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,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