jugyo-termtter 0.5.8 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/Rakefile +8 -0
- data/lib/plugin/english.rb +29 -20
- data/lib/plugin/favorite.rb +5 -7
- data/lib/plugin/growl.rb +33 -14
- data/lib/plugin/log.rb +2 -0
- data/lib/plugin/plugin.rb +35 -1
- data/lib/plugin/standard_plugins.rb +10 -0
- data/lib/plugin/stdout.rb +15 -13
- data/lib/termtter.rb +46 -12
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -42,7 +42,7 @@ To update the config, just restart your termtter proccess.
|
|
42
42
|
|
43
43
|
(The MIT License)
|
44
44
|
|
45
|
-
Copyright (c) 2008
|
45
|
+
Copyright (c) 2008-2009 The Termtter Development Team
|
46
46
|
|
47
47
|
Permission is hereby granted, free of charge, to any person obtaining
|
48
48
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -28,3 +28,11 @@ Dir['tasks/**/*.rake'].each { |t| load t }
|
|
28
28
|
|
29
29
|
# TODO - want other tests/tasks run by default? Add them to the list
|
30
30
|
# task :default => [:spec, :features]
|
31
|
+
|
32
|
+
require 'spec/rake/spectask'
|
33
|
+
desc 'run all specs'
|
34
|
+
Spec::Rake::SpecTask.new do |t|
|
35
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
36
|
+
t.spec_opts = ['-c']
|
37
|
+
end
|
38
|
+
|
data/lib/plugin/english.rb
CHANGED
@@ -1,51 +1,60 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
1
3
|
Termtter::Client.clear_hooks # FIXME: not to clear all but to clear just stdout.rb
|
2
4
|
|
5
|
+
configatron.set_default(
|
6
|
+
:timeline_format,
|
7
|
+
'<%= color(time, 90) %> <%= color(status, status_color) %> <%= color(id, 90) %>')
|
8
|
+
|
3
9
|
# english? :: String -> Boolean
|
4
10
|
def english?(message)
|
5
|
-
/[
|
11
|
+
/[��-��]+|[��-��]+|[��-����]+|[��-����-�ڣ�-��]+/ !~ message
|
12
|
+
end
|
13
|
+
|
14
|
+
def color(str, num)
|
15
|
+
"\e[#{num}m#{str}\e[0m"
|
6
16
|
end
|
7
17
|
|
8
18
|
# FIXME: The code below is a copy from stdout.rb so it's not DRY. DRY it.
|
19
|
+
|
9
20
|
Termtter::Client.add_hook do |statuses, event|
|
10
21
|
colors = %w(0 31 32 33 34 35 36 91 92 93 94 95 96)
|
11
22
|
|
12
23
|
case event
|
13
24
|
when :update_friends_timeline, :list_friends_timeline, :list_user_timeline, :show, :replies
|
14
25
|
unless statuses.empty?
|
15
|
-
if event == :update_friends_timeline
|
26
|
+
statuses.reverse! if event == :update_friends_timeline
|
16
27
|
statuses.each do |s|
|
17
28
|
text = s.text.gsub("\n", '')
|
18
29
|
next unless english?(text) # if you substitute "if" for "unless", this script will be "japanese.rb"
|
19
|
-
|
30
|
+
status_color = colors[s.user_screen_name.hash % colors.size]
|
20
31
|
status = "#{s.user_screen_name}: #{text}"
|
21
32
|
if s.in_reply_to_status_id
|
22
33
|
status += " (reply to #{s.in_reply_to_status_id})"
|
23
34
|
end
|
24
35
|
|
25
|
-
case event
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
36
|
+
time_format = case event
|
37
|
+
when :update_friends_timeline, :list_friends_timeline
|
38
|
+
'%H:%M:%S'
|
39
|
+
else
|
40
|
+
'%m-%d %H:%M'
|
41
|
+
end
|
42
|
+
time = "(#{s.created_at.strftime(time_format)})"
|
43
|
+
|
44
|
+
id = s.id
|
32
45
|
|
33
|
-
puts
|
46
|
+
puts ERB.new(configatron.timeline_format).result(binding)
|
34
47
|
end
|
35
48
|
end
|
36
49
|
when :search
|
37
50
|
statuses.each do |s|
|
38
51
|
text = s.text.gsub("\n", '')
|
39
|
-
|
40
|
-
status = "#{s.user_screen_name}: #{text}"
|
41
|
-
time_str = "(#{s.created_at.strftime('%m-%d %H:%d')})"
|
52
|
+
status_color = colors[s.user_screen_name.hash % colors.size]
|
42
53
|
|
43
|
-
|
54
|
+
status = "#{s.user_screen_name}: #{text}"
|
55
|
+
time = "(#{s.created_at.strftime('%m-%d %H:%M')})"
|
56
|
+
id = s.id
|
57
|
+
puts ERB.new(configatron.timeline_format).result(binding)
|
44
58
|
end
|
45
59
|
end
|
46
60
|
end
|
47
|
-
|
48
|
-
# USAGE:
|
49
|
-
# Write the line on the *first line* of your ~/.termtter
|
50
|
-
# plugin 'english'
|
51
|
-
# (english.rb will destroy plugins which were required before)
|
data/lib/plugin/favorite.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Termtter::Client
|
2
|
+
add_help 'favorite,fav ID', 'Favorite a status'
|
3
|
+
|
2
4
|
add_command %r'^(?:favorite|fav)\s+(\d+)$' do |m,t|
|
3
5
|
id = m[1]
|
4
6
|
res = t.favorite(id)
|
@@ -10,6 +12,8 @@ module Termtter::Client
|
|
10
12
|
end
|
11
13
|
|
12
14
|
if public_storage[:log]
|
15
|
+
add_help 'favorite,fav /word', 'Favorite a status by searching'
|
16
|
+
|
13
17
|
add_command %r'^(?:favorite|fav)\s+/(.+)$' do |m,t|
|
14
18
|
pat = Regexp.new(m[1])
|
15
19
|
statuses = public_storage[:log].select { |s| s.text =~ pat }
|
@@ -32,15 +36,9 @@ module Termtter
|
|
32
36
|
class Twitter
|
33
37
|
def favorite(id)
|
34
38
|
uri = "http://twitter.com/favourings/create/#{id}.json"
|
35
|
-
req = Net::HTTP::Post.new(uri)
|
36
|
-
req.basic_auth(@user_name, @password)
|
37
|
-
req.add_field('User-Agent', 'Termtter http://github.com/jugyo/termtter')
|
38
|
-
req.add_field('X-Twitter-Client', 'Termtter')
|
39
|
-
req.add_field('X-Twitter-Client-URL', 'http://github.com/jugyo/termtter')
|
40
|
-
req.add_field('X-Twitter-Client-Version', '0.1')
|
41
39
|
|
42
40
|
Net::HTTP.start('twitter.com', 80) do |http|
|
43
|
-
http.request(
|
41
|
+
http.request(post_request(uri))
|
44
42
|
end
|
45
43
|
end
|
46
44
|
end
|
data/lib/plugin/growl.rb
CHANGED
@@ -1,29 +1,48 @@
|
|
1
1
|
require 'tmpdir'
|
2
|
+
require 'open-uri'
|
2
3
|
require 'uri'
|
3
4
|
|
5
|
+
configatron.plugins.growl.set_default(:icon_cache_dir, "#{Dir.tmpdir}/termtter-icon-cache-dir")
|
6
|
+
Dir.mkdir_p(configatron.plugins.growl.icon_cache_dir) unless File.exist?(configatron.plugins.growl.icon_cache_dir)
|
7
|
+
|
4
8
|
def get_icon_path(s)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
cache_file = "%s/%s%s" % [ configatron.plugins.growl.icon_cache_dir,
|
10
|
+
s.user_screen_name,
|
11
|
+
File.extname(s.user_profile_image_url) ]
|
12
|
+
if File.exist?(cache_file) && (File.atime(cache_file) + 24*60*60) > Time.now
|
13
|
+
return cache_file
|
14
|
+
else
|
15
|
+
Thread.new do
|
16
|
+
File.open(cache_file, "wb") do |f|
|
17
|
+
f << open(URI.escape(s.user_profile_image_url)).read
|
18
|
+
end
|
12
19
|
end
|
13
|
-
|
14
|
-
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
queue = []
|
25
|
+
Thread.new do
|
26
|
+
loop do
|
27
|
+
begin
|
28
|
+
if s = queue.pop
|
29
|
+
arg = ['growlnotify', s.user_screen_name, '-m', s.text.gsub("\n",''), '-n', 'termtter']
|
30
|
+
#icon_path = get_icon_path(s)
|
31
|
+
#arg += ['--image', icon_path] if icon_path
|
32
|
+
system *arg
|
33
|
+
end
|
34
|
+
rescue => e
|
35
|
+
puts e
|
36
|
+
puts e.backtrace.join("\n")
|
15
37
|
end
|
38
|
+
sleep 0.1
|
16
39
|
end
|
17
|
-
cache_file
|
18
40
|
end
|
19
41
|
|
20
42
|
Termtter::Client.add_hook do |statuses, event|
|
21
43
|
if !statuses.empty? && event == :update_friends_timeline
|
22
44
|
statuses.reverse.each do |s|
|
23
|
-
|
24
|
-
icon_path = get_icon_path(s)
|
25
|
-
system 'growlnotify', s.user_screen_name, '-m', text,
|
26
|
-
'-n', 'termtter', '--image', icon_path
|
45
|
+
queue << s
|
27
46
|
end
|
28
47
|
end
|
29
48
|
end
|
data/lib/plugin/log.rb
CHANGED
data/lib/plugin/plugin.rb
CHANGED
@@ -1,6 +1,39 @@
|
|
1
1
|
module Termtter::Client
|
2
|
+
|
3
|
+
public_storage[:plugins] = Dir["#{File.dirname(__FILE__)}/*.rb"].map do |f|
|
4
|
+
f.match(%r|([^/]+).rb$|)[1]
|
5
|
+
end
|
6
|
+
|
7
|
+
add_help 'plugin FILE', 'Load a plugin'
|
2
8
|
add_command /^plugin\s+(.*)/ do |m, t|
|
3
|
-
|
9
|
+
begin
|
10
|
+
result = plugin m[1].strip
|
11
|
+
rescue LoadError
|
12
|
+
ensure
|
13
|
+
puts "=> #{result.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
add_help 'plugins', 'Show list of plugins'
|
18
|
+
add_command /^plugins$/ do |m, t|
|
19
|
+
puts public_storage[:plugins].join("\n")
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.find_plugin_candidates(a, b)
|
23
|
+
if a.empty?
|
24
|
+
public_storage[:plugins].to_a
|
25
|
+
else
|
26
|
+
public_storage[:plugins].grep(/^#{Regexp.quote a}/i)
|
27
|
+
end.
|
28
|
+
map {|u| b % u }
|
29
|
+
end
|
30
|
+
|
31
|
+
add_completion do |input|
|
32
|
+
if input =~ /^(plugin)\s+(.*)/
|
33
|
+
find_plugin_candidates $2, "#{$1} %s"
|
34
|
+
else
|
35
|
+
%w[ plugin plugins ].grep(/^#{Regexp.quote input}/)
|
36
|
+
end
|
4
37
|
end
|
5
38
|
end
|
6
39
|
|
@@ -10,5 +43,6 @@ end
|
|
10
43
|
# > u <%= not erbed %>
|
11
44
|
# => <%= not erbed %>
|
12
45
|
# > plugin erb
|
46
|
+
# => true
|
13
47
|
# > u <%= 1 + 2 %>
|
14
48
|
# => 3
|
@@ -57,6 +57,7 @@ replies,r List the most recent @replies for the authenticating user
|
|
57
57
|
search,s TEXT Search for Twitter
|
58
58
|
show ID Show a single status
|
59
59
|
EOS
|
60
|
+
puts formatted_help unless @@helps.empty?
|
60
61
|
end
|
61
62
|
|
62
63
|
add_command /^eval\s+(.*)$/ do |m, t|
|
@@ -68,6 +69,15 @@ show ID Show a single status
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
72
|
+
def self.formatted_help
|
73
|
+
width = @@helps.map {|n, d| n.size }.max
|
74
|
+
space = 3
|
75
|
+
"\nuser commands:\n" +
|
76
|
+
@@helps.map {|name, desc|
|
77
|
+
name.to_s.ljust(width + space) + desc.to_s
|
78
|
+
}.join("\n")
|
79
|
+
end
|
80
|
+
|
71
81
|
# completion for standard commands
|
72
82
|
|
73
83
|
require 'set'
|
data/lib/plugin/stdout.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'erb'
|
2
2
|
|
3
|
-
configatron.set_default(
|
3
|
+
configatron.set_default(
|
4
|
+
:timeline_format,
|
5
|
+
'<%= color(time, 90) %> <%= color(status, status_color) %> <%= color(id, 90) %>')
|
4
6
|
|
5
7
|
def color(str, num)
|
6
8
|
"\e[#{num}m#{str}\e[0m"
|
@@ -12,34 +14,34 @@ Termtter::Client.add_hook do |statuses, event|
|
|
12
14
|
case event
|
13
15
|
when :update_friends_timeline, :list_friends_timeline, :list_user_timeline, :show, :replies
|
14
16
|
unless statuses.empty?
|
15
|
-
if event == :update_friends_timeline
|
17
|
+
statuses.reverse! if event == :update_friends_timeline
|
16
18
|
statuses.each do |s|
|
17
19
|
text = s.text.gsub("\n", '')
|
18
|
-
|
20
|
+
status_color = colors[s.user_screen_name.hash % colors.size]
|
19
21
|
status = "#{s.user_screen_name}: #{text}"
|
20
22
|
if s.in_reply_to_status_id
|
21
23
|
status += " (reply to #{s.in_reply_to_status_id})"
|
22
24
|
end
|
23
25
|
|
24
|
-
case event
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
time_format = case event
|
27
|
+
when :update_friends_timeline, :list_friends_timeline
|
28
|
+
'%H:%M:%S'
|
29
|
+
else
|
30
|
+
'%m-%d %H:%M'
|
31
|
+
end
|
31
32
|
time = "(#{s.created_at.strftime(time_format)})"
|
32
|
-
|
33
|
+
|
33
34
|
id = s.id
|
35
|
+
|
34
36
|
puts ERB.new(configatron.timeline_format).result(binding)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
when :search
|
38
40
|
statuses.each do |s|
|
39
41
|
text = s.text.gsub("\n", '')
|
40
|
-
|
42
|
+
status_color = colors[s.user_screen_name.hash % colors.size]
|
41
43
|
|
42
|
-
status =
|
44
|
+
status = "#{s.user_screen_name}: #{text}"
|
43
45
|
time = "(#{s.created_at.strftime('%m-%d %H:%M')})"
|
44
46
|
id = s.id
|
45
47
|
puts ERB.new(configatron.timeline_format).result(binding)
|
data/lib/termtter.rb
CHANGED
@@ -7,6 +7,12 @@ require 'enumerator'
|
|
7
7
|
require 'parsedate'
|
8
8
|
require 'configatron'
|
9
9
|
|
10
|
+
if RUBY_VERSION < '1.8.7'
|
11
|
+
class Array
|
12
|
+
def take(n) at(0...n) end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
10
16
|
$:.unshift(File.dirname(__FILE__)) unless
|
11
17
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
12
18
|
|
@@ -22,14 +28,15 @@ alias original_require require
|
|
22
28
|
def require(s)
|
23
29
|
if %r|^termtter/(.*)| =~ s
|
24
30
|
puts "[WARNING] use plugin '#{$1}' instead of require"
|
25
|
-
|
26
|
-
|
27
|
-
original_require s
|
31
|
+
puts " Such a legacy .termtter file will not be supported until version 1.0.0"
|
32
|
+
s = "plugin/#{$1}"
|
28
33
|
end
|
34
|
+
original_require s
|
29
35
|
end
|
30
36
|
|
31
37
|
module Termtter
|
32
|
-
VERSION = '0.
|
38
|
+
VERSION = '0.6.0'
|
39
|
+
APP_NAME = 'termtter'
|
33
40
|
|
34
41
|
class Twitter
|
35
42
|
|
@@ -39,14 +46,9 @@ module Termtter
|
|
39
46
|
end
|
40
47
|
|
41
48
|
def update_status(status)
|
42
|
-
req = Net::HTTP::Post.new('/statuses/update.xml')
|
43
|
-
req.basic_auth(@user_name, @password)
|
44
|
-
req.add_field("User-Agent", "Termtter http://github.com/jugyo/termtter")
|
45
|
-
req.add_field("X-Twitter-Client", "Termtter")
|
46
|
-
req.add_field("X-Twitter-Client-URL", "http://github.com/jugyo/termtter")
|
47
|
-
req.add_field("X-Twitter-Client-Version", "0.1")
|
48
49
|
Net::HTTP.start("twitter.com", 80) do |http|
|
49
|
-
|
50
|
+
uri = '/statuses/update.xml'
|
51
|
+
http.request(post_request(uri), "status=#{CGI.escape(status)}&source=#{APP_NAME}")
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
@@ -58,6 +60,11 @@ module Termtter
|
|
58
60
|
|
59
61
|
def get_user_timeline(screen_name)
|
60
62
|
return get_timeline("http://twitter.com/statuses/user_timeline/#{screen_name}.json")
|
63
|
+
rescue OpenURI::HTTPError => e
|
64
|
+
puts "No such user: #{screen_name}"
|
65
|
+
nears = near_users(screen_name)
|
66
|
+
puts "near users: #{nears}" unless nears.empty?
|
67
|
+
return {}
|
61
68
|
end
|
62
69
|
|
63
70
|
def search(query)
|
@@ -65,7 +72,7 @@ module Termtter
|
|
65
72
|
return results.map do |s|
|
66
73
|
status = Status.new
|
67
74
|
status.id = s['id']
|
68
|
-
status.text = s['text']
|
75
|
+
status.text = CGI.unescapeHTML(s['text'])
|
69
76
|
status.created_at = Time.utc(*ParseDate::parsedate(s["created_at"])).localtime
|
70
77
|
status.user_screen_name = s['from_user']
|
71
78
|
status
|
@@ -92,9 +99,27 @@ module Termtter
|
|
92
99
|
%w(id name screen_name url profile_image_url).each do |key|
|
93
100
|
status.__send__("user_#{key}=".to_sym, s["user"][key])
|
94
101
|
end
|
102
|
+
status.text = CGI.unescapeHTML(status.text)
|
95
103
|
status
|
96
104
|
end
|
97
105
|
end
|
106
|
+
|
107
|
+
def near_users(screen_name)
|
108
|
+
Client::public_storage[:users].select {|user|
|
109
|
+
/#{user}/i =~ screen_name || /#{screen_name}/i =~ user
|
110
|
+
}.join(', ')
|
111
|
+
end
|
112
|
+
private :near_users
|
113
|
+
|
114
|
+
def post_request(uri)
|
115
|
+
req = Net::HTTP::Post.new(uri)
|
116
|
+
req.basic_auth(@user_name, @password)
|
117
|
+
req.add_field('User-Agent', 'Termtter http://github.com/jugyo/termtter')
|
118
|
+
req.add_field('X-Twitter-Client', 'Termtter')
|
119
|
+
req.add_field('X-Twitter-Client-URL', 'http://github.com/jugyo/termtter')
|
120
|
+
req.add_field('X-Twitter-Client-Version', '0.1')
|
121
|
+
req
|
122
|
+
end
|
98
123
|
end
|
99
124
|
|
100
125
|
module Client
|
@@ -102,6 +127,7 @@ module Termtter
|
|
102
127
|
@@hooks = []
|
103
128
|
@@commands = {}
|
104
129
|
@@completions = []
|
130
|
+
@@helps = []
|
105
131
|
|
106
132
|
class << self
|
107
133
|
def add_hook(&hook)
|
@@ -128,6 +154,14 @@ module Termtter
|
|
128
154
|
@@completions.clear
|
129
155
|
end
|
130
156
|
|
157
|
+
def add_help(name, desc)
|
158
|
+
@@helps << [name, desc]
|
159
|
+
end
|
160
|
+
|
161
|
+
def clear_helps
|
162
|
+
@@helps.clear
|
163
|
+
end
|
164
|
+
|
131
165
|
Readline.basic_word_break_characters= "\t\n\"\\'`><=;|&{("
|
132
166
|
Readline.completion_proc = proc {|input|
|
133
167
|
@@completions.map {|completion|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jugyo-termtter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jugyo
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-01-
|
13
|
+
date: 2009-01-07 00:00:00 -08:00
|
14
14
|
default_executable: termtter
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|