jugyo-termtter 0.4.0 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
data/bin/termtter CHANGED
@@ -23,11 +23,11 @@ else
23
23
  The configuration file does not exist.
24
24
  Example:
25
25
  # ~/.termtter
26
- configatron.user_name = USERNAME
27
- configatron.password = PASSWORD
26
+ configatron.user_name = 'USERNAME'
27
+ configatron.password = 'PASSWORD'
28
28
  EOS
29
29
  exit 1
30
30
  end
31
31
 
32
- Termtter::Client.new.run
32
+ Termtter::Client.run
33
33
 
@@ -2,64 +2,68 @@ class Termtter::Client
2
2
 
3
3
  add_command /^(update|u)\s+(.*)/ do |m, t|
4
4
  text = m[2]
5
- next if text.empty?
6
- t.update_status(text)
7
- puts "=> #{text}"
5
+ unless text.empty?
6
+ t.update_status(text)
7
+ puts "=> #{text}"
8
+ end
8
9
  end
9
10
 
10
11
  add_command /^(list|l)\s*$/ do |m, t|
11
- t.list_friends_timeline()
12
+ statuses = t.get_friends_timeline()
13
+ call_hooks(statuses, :list_friends_timeline, t)
12
14
  end
13
15
 
14
16
  add_command /^(list|l)\s+([^\s]+)/ do |m, t|
15
- t.get_user_timeline(m[2])
17
+ statuses = t.get_user_timeline(m[2])
18
+ call_hooks(statuses, :list_user_timeline, t)
16
19
  end
17
20
 
18
- add_command /^(search|s)\s+(.*)/ do |m, t|
19
- query = m[2]
20
- unless query.empty?
21
- t.search(query)
22
- end
21
+ add_command /^(search|s)\s+(.+)/ do |m, t|
22
+ call_hooks(t.search(m[2]), :search, t)
23
23
  end
24
24
 
25
25
  add_command /^(replies|r)\s*$/ do |m, t|
26
- t.replies()
26
+ call_hooks(t.replies(), :replies, t)
27
27
  end
28
28
 
29
29
  add_command /^show\s+([^\s]+)/ do |m, t|
30
- t.show(m[1])
30
+ call_hooks(t.show(m[1]), :show, t)
31
31
  end
32
32
 
33
33
  add_command /^pause\s*$/ do |m, t|
34
- t.pause
34
+ pause
35
35
  end
36
36
 
37
37
  add_command /^resume\s*$/ do |m, t|
38
- t.resume
38
+ resume
39
39
  end
40
40
 
41
41
  add_command /^exit\s*$/ do |m, t|
42
- t.exit
42
+ exit
43
43
  end
44
44
 
45
45
  add_command /^help\s*$/ do |m, t|
46
46
  puts <<-EOS
47
- exit Exit
48
- help Print this help message
49
- list,l List the posts in your friends timeline
50
- list USERNAME List the posts in the the given user's timeline
51
- pause Pause updating
52
- update,u TEXT Post a new message
53
- resume Resume updating
54
- replies,r List the most recent @replies for the authenticating user
55
- search,s TEXT Search for Twitter
56
- show ID Show a single status
47
+ exit Exit
48
+ help Print this help message
49
+ list,l List the posts in your friends timeline
50
+ list,l USERNAME List the posts in the the given user's timeline
51
+ pause Pause updating
52
+ update,u TEXT Post a new message
53
+ resume Resume updating
54
+ replies,r List the most recent @replies for the authenticating user
55
+ search,s TEXT Search for Twitter
56
+ show ID Show a single status
57
57
  EOS
58
58
  end
59
59
 
60
60
  add_command /^eval\s+(.*)$/ do |m, t|
61
- result = t.instance_eval m[1] unless m[1].empty?
62
- puts "=> #{result.inspect}"
61
+ begin
62
+ result = eval(m[1]) unless m[1].empty?
63
+ puts "=> #{result.inspect}"
64
+ rescue SyntaxError => e
65
+ puts e
66
+ end
63
67
  end
64
68
 
65
69
  end
@@ -6,7 +6,7 @@ Termtter::Client.add_hook do |statuses, event|
6
6
  colors = %w(0 31 32 33 34 35 36 91 92 93 94 95 96)
7
7
 
8
8
  case event
9
- when :update_friends_timeline, :list_friends_timeline, :list_user_timeline, :show
9
+ when :update_friends_timeline, :list_friends_timeline, :list_user_timeline, :show, :replies
10
10
  unless statuses.empty?
11
11
  if event == :update_friends_timeline then statuses = statuses.reverse end
12
12
  statuses.each do |s|
@@ -1,16 +1,16 @@
1
- Termtter::Client.add_hook do |statuses, event, t|
2
- t.public_storage[:uris] ||= []
3
- if !statuses.empty? && event == :update_friends_timeline
4
- statuses.each do |s|
5
- t.public_storage[:uris] += s.text.scan(%r|https?://[^\s]+|)
1
+ class Termtter::Client
2
+ public_storage[:uris] = []
3
+
4
+ add_hook do |statuses, event, t|
5
+ if !statuses.empty? && event == :update_friends_timeline
6
+ statuses.each do |s|
7
+ public_storage[:uris] += s.text.scan(%r|https?://[^\s]+|)
8
+ end
6
9
  end
7
10
  end
8
- end
9
11
 
10
- class Termtter::Client
11
12
  add_command /^uri-open\s*$/ do |m, t|
12
- t.public_storage[:uris] ||= [] # It's not DRY
13
- t.public_storage[:uris].each do |uri|
13
+ public_storage[:uris].each do |uri|
14
14
  # FIXME: works only in OSX and other *NIXs
15
15
  if /linux/ =~ RUBY_PLATFORM
16
16
  system 'firefox', uri
@@ -18,7 +18,16 @@ class Termtter::Client
18
18
  system 'open', uri
19
19
  end
20
20
  end
21
- t.public_storage[:uris].clear
21
+ public_storage[:uris].clear
22
+ end
23
+
24
+ add_command /^uri-open\s+list\s*$/ do |m, t|
25
+ puts public_storage[:uris]
26
+ end
27
+
28
+ add_command /^uri-open\s+clear\s*$/ do |m, t|
29
+ public_storage[:uris].clear
30
+ puts "clear uris"
22
31
  end
23
32
  end
24
33
  # ~/.termtter
data/lib/termtter.rb CHANGED
@@ -10,41 +10,13 @@ $:.unshift(File.dirname(__FILE__)) unless
10
10
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
11
11
 
12
12
  module Termtter
13
- VERSION = '0.4.0'
13
+ VERSION = '0.4.5'
14
14
 
15
- class CommandNotFound < StandardError; end
16
-
17
- class Client
18
-
19
- @@hooks = []
20
- @@commands = {}
21
-
22
- def self.add_hook(&hook)
23
- @@hooks << hook
24
- end
25
-
26
- def self.clear_hooks
27
- @@hooks.clear
28
- end
29
-
30
- def self.add_command(regex, &block)
31
- @@commands[regex] = block
32
- end
33
-
34
- def self.clear_commands
35
- @@commands.clear
36
- end
37
-
38
- attr_reader :since_id, :public_storage
15
+ class Twitter
39
16
 
40
- def initialize
41
- configatron.set_default(:update_interval, 300)
42
- configatron.set_default(:debug, false)
43
- @user_name = configatron.user_name
44
- @password = configatron.password
45
- @update_interval = configatron.update_interval
46
- @debug = configatron.debug
47
- @public_storage = {}
17
+ def initialize(user_name, password)
18
+ @user_name = user_name
19
+ @password = password
48
20
  end
49
21
 
50
22
  def update_status(status)
@@ -59,70 +31,43 @@ module Termtter
59
31
  end
60
32
  end
61
33
 
62
- def list_friends_timeline
63
- statuses = get_timeline("http://twitter.com/statuses/friends_timeline.json")
64
- call_hooks(statuses, :list_friends_timeline)
65
- end
66
-
67
- def update_friends_timeline
34
+ def get_friends_timeline(since_id = nil)
68
35
  uri = "http://twitter.com/statuses/friends_timeline.json"
69
- if @since_id
70
- uri += "?since_id=#{@since_id}"
71
- end
72
-
73
- statuses = get_timeline(uri, true)
74
- call_hooks(statuses, :update_friends_timeline)
36
+ uri += "?since_id=#{since_id}" if since_id
37
+ return get_timeline(uri)
75
38
  end
76
39
 
77
40
  def get_user_timeline(screen_name)
78
- statuses = get_timeline("http://twitter.com/statuses/user_timeline/#{screen_name}.json")
79
- call_hooks(statuses, :list_user_timeline)
41
+ return get_timeline("http://twitter.com/statuses/user_timeline/#{screen_name}.json")
80
42
  end
81
43
 
82
44
  def search(query)
83
- statuses = []
84
-
85
45
  results = JSON.parse(open('http://search.twitter.com/search.json?q=' + CGI.escape(query)).read)['results']
86
- results.each do |s|
46
+ return results.inject([]) do |statuses, s|
87
47
  status = Status.new
88
48
  status.text = s['text']
89
49
  status.created_at = Time.utc(*ParseDate::parsedate(s["created_at"])).localtime
90
50
  status.user_screen_name = s['from_user']
91
51
  statuses << status
92
52
  end
93
-
94
- call_hooks(statuses, :search)
95
- return statuses
96
53
  end
97
54
 
98
55
  def show(id)
99
- statuses = get_timeline("http://twitter.com/statuses/show/#{id}.json")
100
- call_hooks(statuses, :show)
56
+ return get_timeline("http://twitter.com/statuses/show/#{id}.json")
101
57
  end
102
58
 
103
59
  def replies
104
- statuses = get_timeline("http://twitter.com/statuses/replies.json")
105
- call_hooks(statuses, :show)
106
- end
107
-
108
- def call_hooks(statuses, event)
109
- @@hooks.each do |h|
110
- begin
111
- h.call(statuses.dup, event, self)
112
- rescue => e
113
- puts "Error: #{e}"
114
- puts e.backtrace.join("\n")
115
- end
116
- end
60
+ return get_timeline("http://twitter.com/statuses/replies.json")
117
61
  end
118
62
 
119
- def get_timeline(uri, update_since_id = false)
120
- statuses = []
121
-
63
+ def get_timeline(uri)
122
64
  data = JSON.parse(open(uri, :http_basic_authentication => [@user_name, @password]).read)
123
- data = if data.instance_of? Array then data else [data] end
124
-
125
- data.each do |s|
65
+ data = if data.instance_of? Array
66
+ data
67
+ else
68
+ [data]
69
+ end
70
+ return data.inject([]) do |statuses, s|
126
71
  u = s["user"]
127
72
  status = Status.new
128
73
  status.created_at = Time.utc(*ParseDate::parsedate(s["created_at"])).localtime
@@ -134,15 +79,47 @@ module Termtter
134
79
  end
135
80
  statuses << status
136
81
  end
82
+ end
83
+ end
137
84
 
138
- if update_since_id && !statuses.empty?
139
- @since_id = statuses[0].id
140
- end
85
+ class Client
86
+
87
+ @@hooks = []
88
+ @@commands = {}
89
+
90
+ def self.add_hook(&hook)
91
+ @@hooks << hook
92
+ end
93
+
94
+ def self.clear_hooks
95
+ @@hooks.clear
96
+ end
97
+
98
+ def self.add_command(regex, &block)
99
+ @@commands[regex] = block
100
+ end
101
+
102
+ def self.clear_commands
103
+ @@commands.clear
104
+ end
105
+
106
+ def self.public_storage
107
+ @@public_storage ||= {}
108
+ return @@public_storage
109
+ end
141
110
 
142
- return statuses
111
+ def self.call_hooks(statuses, event, tw)
112
+ @@hooks.each do |h|
113
+ begin
114
+ h.call(statuses.dup, event, tw)
115
+ rescue => e
116
+ puts "Error: #{e}"
117
+ puts e.backtrace.join("\n")
118
+ end
119
+ end
143
120
  end
144
121
 
145
- def call_commands(text)
122
+ def self.call_commands(text, tw)
146
123
  return if text.empty?
147
124
 
148
125
  command_found = false
@@ -150,7 +127,7 @@ module Termtter
150
127
  if key =~ text
151
128
  command_found = true
152
129
  begin
153
- command.call($~, self)
130
+ command.call($~, tw)
154
131
  rescue => e
155
132
  puts "Error: #{e}"
156
133
  puts e.backtrace.join("\n")
@@ -161,37 +138,49 @@ module Termtter
161
138
  raise CommandNotFound unless command_found
162
139
  end
163
140
 
164
- def pause
165
- @pause = true
141
+ def self.pause
142
+ @@pause = true
166
143
  end
167
144
 
168
- def resume
169
- @pause = false
170
- @update.run
145
+ def self.resume
146
+ @@pause = false
147
+ @@update.run
171
148
  end
172
149
 
173
- def exit
174
- @update.kill
175
- @input.kill
150
+ def self.exit
151
+ @@update.kill
152
+ @@input.kill
176
153
  end
177
154
 
178
- def run
179
- @pause = false
155
+ def self.run
156
+ @@pause = false
157
+ tw = Termtter::Twitter.new(configatron.user_name, configatron.password)
180
158
 
181
- @update = Thread.new do
159
+ @@update = Thread.new do
160
+ since_id = nil
182
161
  loop do
183
- if @pause
184
- Thread.stop
162
+ begin
163
+ Thread.stop if @@pause
164
+
165
+ statuses = tw.get_friends_timeline(since_id)
166
+ unless statuses.empty?
167
+ since_id = statuses[0].id
168
+ end
169
+ call_hooks(statuses, :update_friends_timeline, tw)
170
+
171
+ rescue => e
172
+ puts "Error: #{e}"
173
+ puts e.backtrace.join("\n")
174
+ ensure
175
+ sleep configatron.update_interval
185
176
  end
186
- update_friends_timeline()
187
- sleep @update_interval
188
177
  end
189
178
  end
190
179
 
191
- @input = Thread.new do
180
+ @@input = Thread.new do
192
181
  while buf = Readline.readline("", true)
193
182
  begin
194
- call_commands(buf)
183
+ call_commands(buf, tw)
195
184
  rescue CommandNotFound => e
196
185
  puts "Unknown command \"#{buf}\""
197
186
  puts 'Enter "help" for instructions'
@@ -203,13 +192,15 @@ module Termtter
203
192
  end
204
193
 
205
194
  stty_save = `stty -g`.chomp
206
- trap("INT") { system "stty", stty_save; self.exit }
195
+ trap("INT") { system "stty", stty_save; exit }
207
196
 
208
- @input.join
197
+ @@input.join
209
198
  end
210
199
 
211
200
  end
212
201
 
202
+ class CommandNotFound < StandardError; end
203
+
213
204
  class Status
214
205
  %w(
215
206
  id text created_at truncated in_reply_to_status_id in_reply_to_user_id
@@ -1,3 +1,5 @@
1
- [{"in_reply_to_user_id":null,"truncated":false,"created_at":"Sat Jan 03 12:13:45 +0000 2009","user":{"description":"test2 xxxx","followers_count":102,"profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/000\/102.png","url":"http:\/\/twitter.com/test2","name":"Test User 2","protected":false,"screen_name":"test2","location":"Tokyo2","id":102},"favorited":false,"in_reply_to_screen_name":null,"text":"texttext 2","id":10002,"in_reply_to_status_id":null,"source":"<a href=\"http:\/\/ssss2\">ssss2<\/a>"},
1
+ [
2
+ {"in_reply_to_user_id":null,"truncated":false,"created_at":"Sat Jan 03 12:13:45 +0000 2009","user":{"description":"test2 xxxx","followers_count":102,"profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/000\/102.png","url":"http:\/\/twitter.com/test2","name":"Test User 2","protected":false,"screen_name":"test2","location":"Tokyo2","id":102},"favorited":false,"in_reply_to_screen_name":null,"text":"texttext 2","id":10002,"in_reply_to_status_id":null,"source":"<a href=\"http:\/\/ssss2\">ssss2<\/a>"},
2
3
  {"in_reply_to_user_id":null,"truncated":false,"created_at":"Sat Jan 03 12:13:45 +0000 2009","user":{"description":"test1 xxxx","followers_count":101,"profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/000\/101.png","url":"http:\/\/twitter.com/test1","name":"Test User 1","protected":false,"screen_name":"test1","location":"Tokyo1","id":101},"favorited":false,"in_reply_to_screen_name":null,"text":"texttext 1","id":10001,"in_reply_to_status_id":null,"source":"<a href=\"http:\/\/ssss1\">ssss1<\/a>"},
3
- {"in_reply_to_user_id":null,"truncated":false,"created_at":"Sat Jan 03 12:13:45 +0000 2009","user":{"description":"test0 xxxx","followers_count":100,"profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/000\/100.png","url":"http:\/\/twitter.com/test0","name":"Test User 0","protected":false,"screen_name":"test0","location":"Tokyo0","id":100},"favorited":false,"in_reply_to_screen_name":null,"text":"texttext 0","id":10000,"in_reply_to_status_id":null,"source":"<a href=\"http:\/\/ssss0\">ssss0<\/a>"},
4
+ {"in_reply_to_user_id":null,"truncated":false,"created_at":"Sat Jan 03 12:13:45 +0000 2009","user":{"description":"test0 xxxx","followers_count":100,"profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/000\/100.png","url":"http:\/\/twitter.com/test0","name":"Test User 0","protected":false,"screen_name":"test0","location":"Tokyo0","id":100},"favorited":false,"in_reply_to_screen_name":null,"text":"texttext 0","id":10000,"in_reply_to_status_id":null,"source":"<a href=\"http:\/\/ssss0\">ssss0<\/a>"}
5
+ ]
@@ -4,11 +4,11 @@ require 'test/unit'
4
4
  require 'kagemusha'
5
5
  require File.dirname(__FILE__) + '/../lib/termtter'
6
6
 
7
+ # TODO: もっとテスト書く!
8
+
7
9
  class TestTermtter < Test::Unit::TestCase
8
10
  def setup
9
- configatron.user_name = 'test'
10
- configatron.password = 'test'
11
- @termtter = Termtter::Client.new
11
+ @twitter = Termtter::Twitter.new('test', 'test')
12
12
 
13
13
  Termtter::Client.add_hook do |statuses, event|
14
14
  @statuses = statuses
@@ -17,7 +17,7 @@ class TestTermtter < Test::Unit::TestCase
17
17
  end
18
18
 
19
19
  def test_get_timeline
20
- statuses = swap_open('friends_timeline.json') { @termtter.get_timeline('') }
20
+ statuses = swap_open('friends_timeline.json') { @twitter.get_timeline('') }
21
21
 
22
22
  assert_equal 3, statuses.size
23
23
 
@@ -38,13 +38,8 @@ class TestTermtter < Test::Unit::TestCase
38
38
  assert_equal 'Sat Jan 03 21:13:45 +0900 2009', statuses[2].created_at.to_s
39
39
  end
40
40
 
41
- def test_get_timeline_with_update_since_id
42
- statuses = swap_open('friends_timeline.json') { @termtter.get_timeline('', true) }
43
- assert_equal 10002, @termtter.since_id
44
- end
45
-
46
41
  def test_search
47
- statuses = swap_open('search.json') { @termtter.search('') }
42
+ statuses = swap_open('search.json') { @twitter.search('') }
48
43
  assert_equal 3, statuses.size
49
44
  assert_equal 'test2', statuses[0].user_screen_name
50
45
  assert_equal 'texttext 2', statuses[0].text
@@ -55,41 +50,53 @@ class TestTermtter < Test::Unit::TestCase
55
50
  end
56
51
 
57
52
  def test_add_hook
58
- call_hook = false
59
- Termtter::Client.add_hook do |statuses, event|
60
- call_hook = true
53
+ statuses = nil
54
+ event = nil
55
+ twitter = nil
56
+ Termtter::Client.add_hook do |s, e, t|
57
+ statuses = s
58
+ event = e
59
+ twitter = t
61
60
  end
62
- swap_open('search.json'){ @termtter.search('') }
63
61
 
64
- assert_equal true, call_hook
62
+ Termtter::Client.call_hooks([], :foo, @twitter)
63
+
64
+ assert_equal [], statuses
65
+ assert_equal :foo, event
66
+ assert_equal @twitter, twitter
65
67
 
66
68
  Termtter::Client.clear_hooks()
67
- call_hook = false
68
- @termtter.search('')
69
+ statuses = nil
70
+ event = nil
71
+ Termtter::Client.call_hooks([], :foo, @twitter)
69
72
 
70
- assert_equal false, call_hook
73
+ assert_equal nil, statuses
74
+ assert_equal nil, event
71
75
  end
72
76
 
73
77
  def test_add_command
74
78
  command_text = nil
75
79
  matche_text = nil
76
- Termtter::Client.add_command /foo\s+(.*)/ do |matche, termtter|
77
- command_text = matche[0]
78
- matche_text = matche[1]
80
+ twitter = nil
81
+ Termtter::Client.add_command /foo\s+(.*)/ do |m, t|
82
+ command_text = m[0]
83
+ matche_text = m[1]
84
+ twitter = t
79
85
  end
80
86
 
81
- @termtter.call_commands('foo xxxxxxxxxxxxxx')
87
+ Termtter::Client.call_commands('foo xxxxxxxxxxxxxx', @twitter)
82
88
  assert_equal 'foo xxxxxxxxxxxxxx', command_text
83
89
  assert_equal 'xxxxxxxxxxxxxx', matche_text
90
+ assert_equal @twitter, twitter
84
91
 
85
92
  Termtter::Client.clear_commands()
86
93
  assert_raise Termtter::CommandNotFound do
87
- @termtter.call_commands('foo xxxxxxxxxxxxxx')
94
+ Termtter::Client.call_commands('foo xxxxxxxxxxxxxx', @twitter)
88
95
  end
89
96
  end
90
97
 
91
98
  def swap_open(name)
92
- Kagemusha.new(Termtter::Client).def(:open) {
99
+ Kagemusha.new(Termtter::Twitter).def(:open) {
93
100
  File.open(File.dirname(__FILE__) + "/../test/#{name}")
94
101
  }.swap do
95
102
  yield
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.0
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - jugyo