termtter 1.7.2 → 1.8.0

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 (81) hide show
  1. data/.gitignore +1 -1
  2. data/README.rdoc +1 -0
  3. data/Rakefile +2 -1
  4. data/VERSION +1 -1
  5. data/bin/termtter +1 -0
  6. data/bin/termtter_frame +134 -0
  7. data/lib/plugins/aa.rb +44 -0
  8. data/lib/plugins/another_prompt.rb +42 -41
  9. data/lib/plugins/appendtitle.rb +82 -0
  10. data/lib/plugins/ar.rb +11 -8
  11. data/lib/plugins/async.rb +3 -2
  12. data/lib/plugins/capital_update.rb +12 -0
  13. data/lib/plugins/channel.rb +149 -0
  14. data/lib/plugins/clock.rb +10 -0
  15. data/lib/plugins/defaults/command_line.rb +8 -0
  16. data/lib/plugins/defaults/confirm.rb +1 -1
  17. data/lib/plugins/defaults/hashtag.rb +1 -1
  18. data/lib/plugins/defaults/keyword.rb +11 -0
  19. data/lib/plugins/defaults/list.rb +32 -6
  20. data/lib/plugins/defaults/standard_commands.rb +135 -52
  21. data/lib/plugins/defaults/standard_completion.rb +14 -0
  22. data/lib/plugins/defaults/stdout.rb +59 -27
  23. data/lib/plugins/defaults/user.rb +32 -0
  24. data/lib/plugins/draft.rb +9 -12
  25. data/lib/plugins/easy_post.rb +5 -0
  26. data/lib/plugins/event_invoked_at.rb +23 -0
  27. data/lib/plugins/expand-tinyurl.rb +13 -20
  28. data/lib/plugins/favotter.rb +9 -9
  29. data/lib/plugins/footer.rb +9 -12
  30. data/lib/plugins/friends.rb +0 -26
  31. data/lib/plugins/grass.rb +2 -4
  32. data/lib/plugins/growl.rb +47 -0
  33. data/lib/plugins/gyazo.rb +16 -18
  34. data/lib/plugins/hi.rb +31 -10
  35. data/lib/plugins/http_server.rb +3 -2
  36. data/lib/plugins/irc_gw.rb +71 -17
  37. data/lib/plugins/line.rb +10 -0
  38. data/lib/plugins/linefeed.rb +6 -1
  39. data/lib/plugins/list_switch.rb +76 -0
  40. data/lib/plugins/nop.rb +9 -0
  41. data/lib/plugins/notify-send.rb +1 -1
  42. data/lib/plugins/notify-send2.rb +25 -16
  43. data/lib/plugins/notify-send3.rb +16 -13
  44. data/lib/plugins/nuance.rb +29 -0
  45. data/lib/plugins/open_url.rb +1 -5
  46. data/lib/plugins/random.rb +2 -6
  47. data/lib/plugins/reply_sound.rb +33 -0
  48. data/lib/plugins/say.rb +2 -2
  49. data/lib/plugins/storage/sqlite3.rb +1 -1
  50. data/lib/plugins/story.rb +44 -0
  51. data/lib/plugins/tinyurl.rb +50 -29
  52. data/lib/plugins/translate_tweet.rb +38 -0
  53. data/lib/plugins/web.rb +27 -0
  54. data/lib/termtter.rb +8 -4
  55. data/lib/termtter/client.rb +17 -21
  56. data/lib/termtter/command.rb +35 -13
  57. data/lib/termtter/config.rb +13 -0
  58. data/lib/termtter/config_template.erb +3 -2
  59. data/lib/termtter/default_config.rb +2 -2
  60. data/lib/termtter/event.rb +69 -0
  61. data/lib/termtter/hook.rb +6 -1
  62. data/lib/termtter/hookable.rb +9 -1
  63. data/lib/termtter/httppool.rb +17 -9
  64. data/lib/termtter/optparse.rb +11 -1
  65. data/lib/termtter/rubytter_proxy.rb +21 -5
  66. data/spec/plugins/capital_update_spec.rb +9 -0
  67. data/spec/plugins/fib_spec.rb +2 -4
  68. data/spec/plugins/hi_spec.rb +9 -0
  69. data/spec/plugins/tinyurl_spec.rb +78 -0
  70. data/spec/termtter/client_spec.rb +5 -12
  71. data/spec/termtter/command_spec.rb +22 -10
  72. data/spec/termtter/config_spec.rb +23 -0
  73. data/spec/termtter/event_spec.rb +129 -0
  74. data/spec/termtter/optparse_spec.rb +2 -2
  75. data/spec/termtter/rubytter_proxy_spec.rb +1 -1
  76. metadata +39 -8
  77. data/bin/kill_termtter +0 -22
  78. data/lib/plugins/defaults/users.rb +0 -63
  79. data/lib/plugins/pause.rb +0 -3
  80. data/test/friends_timeline.json +0 -5
  81. data/test/search.json +0 -8
data/.gitignore CHANGED
@@ -2,4 +2,4 @@
2
2
  *~
3
3
  *.gem
4
4
  pkg
5
-
5
+ bin/termtter.bat
data/README.rdoc CHANGED
@@ -74,6 +74,7 @@ You can also type `<` as curry.
74
74
  * termcolor
75
75
  * rubytter
76
76
  * highline
77
+ * notify
77
78
 
78
79
  == TODO:
79
80
 
data/Rakefile CHANGED
@@ -8,10 +8,11 @@ begin
8
8
  gem.summary = "Terminal based Twitter client."
9
9
  gem.description = "Termtter is a terminal based Twitter client."
10
10
  gem.executables = ["termtter"]
11
- gem.add_dependency("json_pure", ">= 1.1.3")
11
+ gem.add_dependency("json", ">= 1.1.3")
12
12
  gem.add_dependency("highline", ">= 1.5.0")
13
13
  gem.add_dependency("termcolor", ">= 1.0.0")
14
14
  gem.add_dependency("rubytter", ">= 0.11.0")
15
+ gem.add_dependency("notify", ">= 0.2.1")
15
16
  gem.authors = %w(jugyo ujihisa)
16
17
  gem.email = 'jugyo.org@gmail.com'
17
18
  gem.homepage = 'http://termtter.org/'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.7.2
1
+ 1.8.0
data/bin/termtter CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- coding: utf-8 -*-
3
+ # vim: filetype=ruby
3
4
 
4
5
  self_file =
5
6
  if File.symlink?(__FILE__)
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ # vim: filetype=ruby
4
+
5
+ self_file =
6
+ if File.symlink?(__FILE__)
7
+ require 'pathname'
8
+ Pathname.new(__FILE__).realpath
9
+ else
10
+ __FILE__
11
+ end
12
+ $:.unshift(File.dirname(self_file) + "/../lib")
13
+ ARGV.unshift '-m' unless ARGV.include?('-m') #monochrome
14
+
15
+ require 'singleton'
16
+ require 'termtter'
17
+
18
+ module Termtter
19
+ class CommandLine
20
+ include Singleton
21
+
22
+ class << self
23
+ def start
24
+ instance.start
25
+ end
26
+
27
+ def stop
28
+ instance.stop
29
+ end
30
+ end
31
+
32
+ def start
33
+ start_input_thread
34
+ end
35
+
36
+ def stop
37
+ @input_thread.kill if @input_thread
38
+ end
39
+
40
+ def call(command_text)
41
+ # Example:
42
+ # t.register_hook(:post_all, :point => :prepare_command) do |s|
43
+ # "update #{s}"
44
+ # end
45
+ Client.get_hooks('prepare_command').each {|hook|
46
+ command_text = hook.call(command_text)
47
+ }
48
+ Client.execute(command_text)
49
+ rescue CommandNotFound => e
50
+ hooks = Client.get_hooks('command_not_found')
51
+ raise e if hooks.empty?
52
+ hooks.each {|hook|
53
+ hook.call(command_text)
54
+ }
55
+ rescue TimeoutError
56
+ puts TermColor.parse("<red>Time out :(</red>")
57
+ end
58
+
59
+ def prompt
60
+ prompt_text = config.prompt
61
+ Client.get_hooks('prepare_prompt').each {|hook|
62
+ prompt_text = hook.call(prompt_text)
63
+ }
64
+ prompt_text
65
+ end
66
+
67
+ private
68
+
69
+ def start_input_thread
70
+ @input_thread = Thread.new do
71
+ buf = ""
72
+ while buf = gets.chomp
73
+ begin
74
+ call(buf)
75
+ rescue Exception => e
76
+ Client.handle_error(e)
77
+ end
78
+ end
79
+ end
80
+ @input_thread.join
81
+ end
82
+
83
+ def do_completion(input)
84
+ end
85
+ end
86
+
87
+ Client.register_hook(:initialize_command_line, :point => :init_command_line) do
88
+ CommandLine.start
89
+ end
90
+
91
+ Client.register_hook(:finalize_command_line, :point => :exit) do
92
+ CommandLine.stop
93
+ end
94
+ end
95
+
96
+ module Termtter::Client
97
+ class << self
98
+ attr_reader :task_manager
99
+ end
100
+ end
101
+
102
+
103
+ config.system.disable_plugins ||= []
104
+ config.system.disable_plugins << :command_line
105
+
106
+ config.__freeze__(:user_name) unless config.user_name.empty?
107
+ Termtter::Client.parse_options
108
+ Termtter::Client.load_config
109
+ Termtter::Client.setup_task_manager
110
+
111
+ Termtter::Client.load_plugins
112
+ Termtter::Client.eval_init_block
113
+ config.__unfreeze__(:user_name)
114
+ Termtter::API.setup
115
+
116
+ config.system.eval_scripts.each do |script|
117
+ begin
118
+ eval script
119
+ rescue Exception => e
120
+ Termtter::Client.handle_error(e)
121
+ end
122
+ end
123
+
124
+ config.system.run_commands.each {|cmd| execute(cmd) }
125
+
126
+ unless config.system.cmd_mode
127
+ Termtter::Client.task_manager.run()
128
+ Termtter::Client.call_hooks(:initialize)
129
+ Termtter::Client.add_task(:name => :call_hooks_after_launched, :after => 1) do
130
+ Termtter::Client.call_hooks(:launched)
131
+ end
132
+ Termtter::Client.call_hooks(:init_command_line)
133
+ end
134
+
data/lib/plugins/aa.rb ADDED
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module AAMaker
4
+ # view-source:http://amachang.sakura.ne.jp/misc/aamaker/
5
+ def self.random(n)
6
+ rand(n).to_i
7
+ end
8
+ def self.randSelect(array)
9
+ return array[random(array.length)]
10
+ end
11
+
12
+ def self.make
13
+ rinkaku = randSelect([['(', ')'], ['(', ')'], ['|', '|'], ['|', '|']]);
14
+ otete = randSelect([['', '', '', '', ''], ['', '', 'm', '', ''], ['', '', 'ლ', '', ''], ['ლ', '', '', 'ლ', ''], ['', '「', '', '', '「'], ['', ' つ', '', '', 'つ'], ['', ' ', '', '', 'o彡゚'], ['', 'n', '', '', 'η'], ['', '∩', '', '∩', ''], ['∩', '', '', '', '∩'], ['ヽ', '', '', '', 'ノ'], ['┐', '', '', '', '┌'], ['╮', '', '', '', '╭'], ['<', '', '', '', '/'], ['╰', '', '', ' ', ''], ['o', '', '', '', 'o'], ['o', '', '', '', 'ツ'], ['', '', '', '', 'ノシ']]);
15
+ omeme = randSelect([['◕', '◕'], ['╹', '╹'], ['>', '<'], ['^', '^'], ['・', '・'], ['´・', '・`'], ['`・', '・´'], ['´', '`'], ['≧', '≦'], ['゚', '゚'], ['\'', '\''], ['・ิ', '・ิ'], ['❛', '❛'], ['⊙', '⊙'], [' ̄', ' ̄'], ['◕ˇ', 'ˇ◕']]);
16
+ okuti = randSelect(['ω', '∀', '▽', '△', 'Д' , '□', '~', 'ー', 'ェ', 'ρ', 'o']);
17
+ hoppe = randSelect([['', ''], ['*', ''], ['', '*'], ['', '#'], ['#', ''], ['✿', ''], ['', '✿'], ['', ';'], [';', ''], ['。', '。'], ['。', ''], ['', '。'], ['▰', '▰'], ['', '▰'], ['▰', ''], ['๑', '๑'], ['', '๑'], ['๑', '']]);
18
+
19
+ text = [
20
+ otete[0],
21
+ rinkaku[0],
22
+ otete[1] || (otete[3] ? '' : hoppe[0]),
23
+ omeme[0],
24
+ otete[2] || okuti,
25
+ omeme[1],
26
+ otete[3] || (otete[1] ? '' : hoppe[1]),
27
+ rinkaku[1],
28
+ otete[4]
29
+ ].join('')
30
+
31
+ text
32
+ end
33
+ end
34
+
35
+ Termtter::Client.register_command(
36
+ :name => :aa,
37
+ :exec_proc => lambda {|arg|
38
+ name = Termtter::Client.normalize_as_user_name(arg)
39
+ command = name.length > 0 ? "u @#{name} #{AAMaker.make}" : "u #{AAMaker.make}"
40
+ Termtter::Client.execute command
41
+ },
42
+ :help => ["aa [(Optinal) USER]", "Post a AA"]
43
+ )
44
+
@@ -1,53 +1,55 @@
1
1
  # -*- coding: utf-8 -*-
2
-
3
2
  config.plugins.another_prompt.
4
- set_default(:shortcut_setting,
5
- { ':' => '',
6
- 'd' => 'direct',
7
- 'D' => 'delete',
8
- 'f' => 'fib',
9
- 'F' => 'favorite',
10
- 'l' => 'list',
11
- 'o' => 'open',
12
- 'p' => 'profile',
13
- 'R' => 'reply',
14
- 's' => 'search',
15
- 't' => 'retweet',
16
- 'u' => 'update',
17
- 'c' => lambda do
18
- system('clear')
19
- end,
20
- 'L' => lambda do
21
- puts '-' *
22
- `stty size`.chomp.
23
- sub(/^\d+\s(\d+)$/, '\\1').to_i
24
- end,
25
- 'q' => lambda do
26
- Termtter::Client.execute('quit')
27
- end,
28
- 'r' => lambda do
29
- Termtter::Client.execute('replies')
30
- end,
31
- '?' => lambda do
32
- Termtter::Client.execute('help')
33
- end,
34
- "\e" => lambda do
35
- system('screen', '-X', 'eval', 'copy')
36
- end
37
- })
3
+ set_default(
4
+ :shortcut_setting,
5
+ {
6
+ ':' => '',
7
+ 'd' => 'direct',
8
+ 'D' => 'delete',
9
+ 'f' => 'fib',
10
+ 'F' => 'favorite',
11
+ 'l' => 'list',
12
+ 'o' => 'open',
13
+ 'p' => 'profile',
14
+ 'R' => 'reply',
15
+ 's' => 'search',
16
+ 't' => 'retweet',
17
+ 'u' => 'update',
18
+ 'c' => lambda do
19
+ system('clear')
20
+ end,
21
+ 'L' => lambda do
22
+ puts '-' *
23
+ `stty size`.chomp.
24
+ sub(/^\d+\s(\d+)$/, '\\1').to_i
25
+ end,
26
+ 'q' => lambda do
27
+ Termtter::Client.execute('quit')
28
+ end,
29
+ 'r' => lambda do
30
+ Termtter::Client.execute('replies')
31
+ end,
32
+ '?' => lambda do
33
+ Termtter::Client.execute('help')
34
+ end,
35
+ "\e" => lambda do
36
+ system('screen', '-X', 'eval', 'copy')
37
+ end
38
+ })
38
39
 
39
40
  Termtter::Client.plug 'curry'
40
41
 
41
42
  module Termtter::Client
42
- add_task(:name => :auto_reload,
43
- :interval => config.update_interval,
44
- :after => config.update_interval) do
43
+ add_task(
44
+ :name => :auto_reload,
45
+ :interval => config.update_interval,
46
+ :after => config.update_interval) do
45
47
  begin
46
48
  execute('reload')
47
49
  rescue Exception => e
48
50
  handle_error(e)
49
51
  end
50
- end
52
+ end
51
53
 
52
54
  register_hook(
53
55
  :name => :auto_reload_init,
@@ -58,8 +60,7 @@ module Termtter::Client
58
60
  rescue Exception => e
59
61
  handle_error(e)
60
62
  end
61
- }
62
- )
63
+ })
63
64
  end
64
65
 
65
66
  module Termtter
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'uri'
3
+ require 'open-uri'
4
+ require 'nokogiri'
5
+ require 'timeout'
6
+ require 'memcache'
7
+ require 'digest/sha1'
8
+
9
+ module Termtter::Client
10
+ config.plugins.appendtitle.set_default(:timeout, 30)
11
+ config.plugins.appendtitle.set_default(:cache_expire, 3600 * 24 * 7)
12
+ config.plugins.appendtitle.set_default(:memcached_server, 'localhost:11211')
13
+
14
+ def self.memcache_client
15
+ @memcache_client ||= MemCache.new(config.plugins.appendtitle.memcached_server)
16
+ end
17
+
18
+ def self.fetch_title(uri)
19
+ return unless uri
20
+ key = %w{ termtter plugins appendtitle title}.push(Digest::SHA1.hexdigest(uri)).join('-')
21
+ if v = memcache_client.get(key)
22
+ logger.debug "appendtitle: cache hit for #{uri}"
23
+ return v
24
+ end
25
+
26
+ memcache_client.set(key, '', config.plugins.appendtitle.cache_expire) # to avoid duplicate fetch
27
+ begin
28
+ logger.debug "appendtitle: fetching title for #{uri}"
29
+ source = Nokogiri(open(uri).read)
30
+ if source and source.at('title')
31
+ title = source.at('title').text
32
+ memcache_client.set(key, title, config.plugins.appendtitle.cache_expire)
33
+ return title
34
+ end
35
+ nil
36
+ rescue Timeout::Error
37
+ nil
38
+ rescue
39
+ nil
40
+ end
41
+ end
42
+
43
+ register_hook(
44
+ :name => :appendtitle,
45
+ :point => :filter_for_output,
46
+ :exec_proc => lambda do |statuses, event|
47
+ threads = statuses.map do |status|
48
+ Thread.new{
49
+ begin
50
+ status.text.gsub!(URI.regexp(['http', 'https'])) {|uri|
51
+ title = fetch_title(uri)
52
+ title = title.gsub(/\n/, '').gsub(/\s+/, ' ') if title
53
+ body_for_compare = status.text.gsub(/\n/, '').gsub(/\s+/, ' ')
54
+ if title and not (
55
+ body_for_compare.include? title or
56
+ body_for_compare.include? title[0..(title.length/2)] or
57
+ body_for_compare.include? title[(title.length/2)..-1]) # XXX: heuristic!!!
58
+ "#{uri} (#{title})"
59
+ else
60
+ uri
61
+ end
62
+ }
63
+ rescue
64
+ end
65
+ }
66
+ end
67
+ begin
68
+ # wait for join or timeout
69
+ timeout(config.plugins.appendtitle.timeout) {
70
+ threads.each{ |t| t.join }
71
+ }
72
+ rescue Timeout::Error
73
+ logger.error 'appendtitle: timeout'
74
+ end
75
+
76
+ statuses
77
+ end
78
+ )
79
+ end
80
+
81
+ # appendtitle.rb:
82
+ # append title for uri.
data/lib/plugins/ar.rb CHANGED
@@ -70,10 +70,12 @@ module Termtter
70
70
  end
71
71
 
72
72
  register_command(:db_search, :alias => :ds) do |arg|
73
- statuses = Status.find(:all,
74
- :conditions => ['text LIKE :l',
75
- {:l => "%" + arg + "%"}],
76
- :limit => 20)
73
+ statuses = Status.find(
74
+ :all,
75
+ :conditions => [
76
+ 'text LIKE :l',
77
+ {:l => "%" + arg + "%"}],
78
+ :limit => 20)
77
79
  output(statuses, :db_search)
78
80
  end
79
81
 
@@ -86,10 +88,11 @@ module Termtter
86
88
 
87
89
  register_command(:db_list) do |arg|
88
90
  user_name = normalize_as_user_name(arg)
89
- statuses = Status.find(:all,
90
- :joins => "LEFT OUTER JOIN users ON users.uid = statuses.user_id",
91
- :conditions => ['users.screen_name = :u',{:u => user_name}],
92
- :limit => 20)
91
+ statuses = Status.find(
92
+ :all,
93
+ :joins => "LEFT OUTER JOIN users ON users.uid = statuses.user_id",
94
+ :conditions => ['users.screen_name = :u',{:u => user_name}],
95
+ :limit => 20)
93
96
  output(statuses, :db_search)
94
97
  end
95
98
 
data/lib/plugins/async.rb CHANGED
@@ -4,10 +4,11 @@ module Termtter::Client
4
4
  :alias => :a,
5
5
  :help => ['async COMMAND', 'asynchronously execute the command'],
6
6
  :completion => lambda {|cmd, arg|
7
- commands.map{|name, command| command.complement(arg)}.
7
+ commands.
8
+ map {|name, command| command.complement(arg) }.
8
9
  flatten.
9
10
  compact.
10
- map{|i| "#{cmd} #{i}"}
11
+ map {|i| "#{cmd} #{i}" }
11
12
  },
12
13
  :exec => lambda {|arg|
13
14
  @task_manager.invoke_later do