jugyo-termtter 0.4.0 → 0.4.5

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