roflbot 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.gitmodules +3 -0
  2. data/Rakefile +1 -0
  3. data/VERSION +1 -1
  4. data/lib/roflbot.rb +1 -0
  5. data/lib/roflbot/base.rb +42 -25
  6. data/roflbot.gemspec +31 -3
  7. data/test/helper.rb +10 -0
  8. data/test/roflbot/test_base.rb +24 -0
  9. data/vendor/gvoice-ruby/Gemfile +11 -0
  10. data/vendor/gvoice-ruby/README.rdoc +71 -0
  11. data/vendor/gvoice-ruby/Rakefile +12 -0
  12. data/vendor/gvoice-ruby/VERSION +1 -0
  13. data/vendor/gvoice-ruby/bin/gv-notifier +75 -0
  14. data/vendor/gvoice-ruby/bin/gv-place-call +18 -0
  15. data/vendor/gvoice-ruby/bin/gv-send-sms +12 -0
  16. data/vendor/gvoice-ruby/config/gvoice-ruby-config.yml.sample +10 -0
  17. data/vendor/gvoice-ruby/lib/gvoice-ruby.rb +6 -0
  18. data/vendor/gvoice-ruby/lib/gvoice-ruby/call.rb +9 -0
  19. data/vendor/gvoice-ruby/lib/gvoice-ruby/client.rb +264 -0
  20. data/vendor/gvoice-ruby/lib/gvoice-ruby/compatibility.rb +37 -0
  21. data/vendor/gvoice-ruby/lib/gvoice-ruby/config.rb +39 -0
  22. data/vendor/gvoice-ruby/lib/gvoice-ruby/inbox_parser.rb +126 -0
  23. data/vendor/gvoice-ruby/lib/gvoice-ruby/sms.rb +9 -0
  24. data/vendor/gvoice-ruby/lib/gvoice-ruby/user.rb +12 -0
  25. data/vendor/gvoice-ruby/lib/gvoice-ruby/voicemail.rb +10 -0
  26. data/vendor/gvoice-ruby/test/client_test.rb +45 -0
  27. data/vendor/gvoice-ruby/test/config_test.rb +37 -0
  28. data/vendor/gvoice-ruby/test/fixtures/config_fixture.yml +10 -0
  29. data/vendor/gvoice-ruby/test/fixtures/inbox.json +1 -0
  30. data/vendor/gvoice-ruby/test/fixtures/inbox.yml +206 -0
  31. data/vendor/gvoice-ruby/test/fixtures/inbox_fixture.html +2854 -0
  32. data/vendor/gvoice-ruby/test/fixtures/login_fixture.html +567 -0
  33. data/vendor/gvoice-ruby/test/gvoice-ruby_test.rb +9 -0
  34. data/vendor/gvoice-ruby/test/inbox_parser_test.rb +54 -0
  35. data/vendor/gvoice-ruby/test/test_helper.rb +19 -0
  36. metadata +31 -3
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/gvoice-ruby"]
2
+ path = vendor/gvoice-ruby
3
+ url = git://github.com/viking/gvoice-ruby.git
data/Rakefile CHANGED
@@ -10,6 +10,7 @@ begin
10
10
  gem.email = "viking415@gmail.com"
11
11
  gem.homepage = "http://github.com/viking/roflbot"
12
12
  gem.authors = ["Jeremy Stephens"]
13
+ gem.files.include("vendor/**/*")
13
14
  gem.add_dependency "net-toc"
14
15
  gem.add_dependency "treetop"
15
16
  gem.add_dependency "twitter"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
@@ -5,6 +5,7 @@ require 'rubygems'
5
5
  require 'net/toc'
6
6
  require 'treetop'
7
7
  require 'twitter'
8
+ require File.dirname(__FILE__) + "/../vendor/gvoice-ruby/lib/gvoice-ruby"
8
9
 
9
10
  module Roflbot
10
11
  end
@@ -1,8 +1,6 @@
1
1
  module Roflbot
2
2
  class Base
3
3
  class Expectation
4
- attr_reader :response
5
-
6
4
  def initialize(regexp)
7
5
  @regexp = regexp
8
6
  end
@@ -18,6 +16,15 @@ module Roflbot
18
16
  @response = message
19
17
  end
20
18
  end
19
+
20
+ def response
21
+ case @response
22
+ when String
23
+ @response
24
+ when Proc
25
+ @response.call
26
+ end
27
+ end
21
28
  end
22
29
 
23
30
  extend Forwardable
@@ -27,22 +34,32 @@ module Roflbot
27
34
  def initialize(options = {})
28
35
  @options = options
29
36
  @expectations = []
37
+ @threads = []
30
38
  accounts = @options["accounts"]
31
39
 
32
40
  @aim = Net::TOC.new(*accounts["AIM"].values_at("username", "password"))
33
41
  @aim.on_im { |m, b, a| on_im(m, b, a) }
34
42
 
35
- oauth = Twitter::OAuth.new(TWITTER[:token], TWITTER[:secret])
36
- oauth.authorize_from_access(*accounts["Twitter"].values_at("token", "secret"))
37
- @twitter = Twitter::Base.new(oauth)
38
- @since_id = accounts['Twitter']['since_id']
39
- end
43
+ if accounts['Twitter']
44
+ oauth = Twitter::OAuth.new(TWITTER[:token], TWITTER[:secret])
45
+ oauth.authorize_from_access(*accounts["Twitter"].values_at("token", "secret"))
46
+ @twitter = Twitter::Base.new(oauth)
47
+ @since_id = accounts['Twitter']['since_id']
48
+ end
40
49
 
41
- def_delegator :@aim, :disconnect
50
+ if accounts['Google Voice']
51
+ @gvoice = GvoiceRuby::Client.new(accounts['Google Voice'])
52
+ end
53
+ end
42
54
 
43
55
  def start
44
56
  @aim.connect
45
- @thread = Thread.new { loop { respond_via_twitter; sleep 60 } }
57
+ if @twitter
58
+ @threads << Thread.new { loop { respond_via_twitter; sleep 60 } }
59
+ end
60
+ if @gvoice
61
+ @threads << Thread.new { loop { respond_via_sms; sleep 60 } }
62
+ end
46
63
  end
47
64
 
48
65
  def wait
@@ -51,7 +68,7 @@ module Roflbot
51
68
 
52
69
  def stop
53
70
  @aim.disconnect
54
- @thread.kill if @thread
71
+ @threads.each { |t| t.kill }
55
72
  end
56
73
 
57
74
  def expects(regexp)
@@ -63,12 +80,7 @@ module Roflbot
63
80
  def on_im(message, buddy, auto_response)
64
81
  @expectations.each do |expectation|
65
82
  next if !expectation.matches?(message)
66
- case expectation.response
67
- when Proc
68
- buddy.send_im(expectation.response.call)
69
- when String
70
- buddy.send_im(expectation.response)
71
- end
83
+ buddy.send_im(expectation.response)
72
84
  break
73
85
  end
74
86
  end
@@ -88,20 +100,25 @@ module Roflbot
88
100
  @expectations.each do |expectation|
89
101
  # throw away beginning mention
90
102
  message = tweet.text.sub(/^@[^\s]+\s+/, "")
91
-
92
103
  next if !expectation.matches?(message)
93
104
 
94
- status =
95
- case expectation.response
96
- when Proc
97
- "@#{tweet.user.screen_name} #{expectation.response.call}"
98
- when String
99
- "@#{tweet.user.screen_name} #{expectation.response}"
100
- end
101
- @twitter.update(status, :in_reply_to_status_id => tweet.id)
105
+ @twitter.update("@#{tweet.user.screen_name} #{expectation.response}", :in_reply_to_status_id => tweet.id)
102
106
  break
103
107
  end
104
108
  end
105
109
  end
110
+
111
+ def respond_via_sms
112
+ @gvoice.check
113
+ return if !@gvoice.any_unread?
114
+
115
+ @gvoice.smss.each do |sms|
116
+ next if !sms.labels.include?("unread")
117
+ @expectations.each do |expectation|
118
+ next if !expectation.matches?(sms.text)
119
+ @gvoice.send_sms(:phone_number => sms.from, :text => expectation.response)
120
+ end
121
+ end
122
+ end
106
123
  end
107
124
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{roflbot}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jeremy Stephens"]
12
- s.date = %q{2010-07-06}
12
+ s.date = %q{2010-07-07}
13
13
  s.default_executable = %q{roflbot}
14
14
  s.description = %q{roflbot will make you a rofl waffle}
15
15
  s.email = %q{viking415@gmail.com}
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  ]
21
21
  s.files = [
22
22
  ".gitignore",
23
+ ".gitmodules",
23
24
  "LICENSE",
24
25
  "README",
25
26
  "Rakefile",
@@ -35,7 +36,34 @@ Gem::Specification.new do |s|
35
36
  "test/helper.rb",
36
37
  "test/roflbot/test_base.rb",
37
38
  "test/roflbot/test_runner.rb",
38
- "test/roflbot/test_sentence_bot.rb"
39
+ "test/roflbot/test_sentence_bot.rb",
40
+ "vendor/gvoice-ruby/Gemfile",
41
+ "vendor/gvoice-ruby/README.rdoc",
42
+ "vendor/gvoice-ruby/Rakefile",
43
+ "vendor/gvoice-ruby/VERSION",
44
+ "vendor/gvoice-ruby/bin/gv-notifier",
45
+ "vendor/gvoice-ruby/bin/gv-place-call",
46
+ "vendor/gvoice-ruby/bin/gv-send-sms",
47
+ "vendor/gvoice-ruby/config/gvoice-ruby-config.yml.sample",
48
+ "vendor/gvoice-ruby/lib/gvoice-ruby.rb",
49
+ "vendor/gvoice-ruby/lib/gvoice-ruby/call.rb",
50
+ "vendor/gvoice-ruby/lib/gvoice-ruby/client.rb",
51
+ "vendor/gvoice-ruby/lib/gvoice-ruby/compatibility.rb",
52
+ "vendor/gvoice-ruby/lib/gvoice-ruby/config.rb",
53
+ "vendor/gvoice-ruby/lib/gvoice-ruby/inbox_parser.rb",
54
+ "vendor/gvoice-ruby/lib/gvoice-ruby/sms.rb",
55
+ "vendor/gvoice-ruby/lib/gvoice-ruby/user.rb",
56
+ "vendor/gvoice-ruby/lib/gvoice-ruby/voicemail.rb",
57
+ "vendor/gvoice-ruby/test/client_test.rb",
58
+ "vendor/gvoice-ruby/test/config_test.rb",
59
+ "vendor/gvoice-ruby/test/fixtures/config_fixture.yml",
60
+ "vendor/gvoice-ruby/test/fixtures/inbox.json",
61
+ "vendor/gvoice-ruby/test/fixtures/inbox.yml",
62
+ "vendor/gvoice-ruby/test/fixtures/inbox_fixture.html",
63
+ "vendor/gvoice-ruby/test/fixtures/login_fixture.html",
64
+ "vendor/gvoice-ruby/test/gvoice-ruby_test.rb",
65
+ "vendor/gvoice-ruby/test/inbox_parser_test.rb",
66
+ "vendor/gvoice-ruby/test/test_helper.rb"
39
67
  ]
40
68
  s.homepage = %q{http://github.com/viking/roflbot}
41
69
  s.rdoc_options = ["--charset=UTF-8"]
@@ -23,6 +23,8 @@ class Test::Unit::TestCase
23
23
  @twitter = stub("Twitter", :mentions => [])
24
24
  Twitter::OAuth.stubs(:new).returns(@oauth)
25
25
  Twitter::Base.stubs(:new).returns(@twitter)
26
+ @gvoice = stub("Gvoice", :smss => [])
27
+ GvoiceRuby::Client.stubs(:new).returns(@gvoice)
26
28
  end
27
29
 
28
30
  def receive_im(message, auto = false)
@@ -33,6 +35,14 @@ class Test::Unit::TestCase
33
35
  Hashie::Mash.new("user" => { "screen_name" => "dudeguy" }, "text" => "@roflbot #{message}", "id" => id)
34
36
  end
35
37
 
38
+ def fake_sms(message)
39
+ stub("SMS", {
40
+ :text => message,
41
+ :from => "+16158675309",
42
+ :labels => %w{unread}
43
+ })
44
+ end
45
+
36
46
  def fixture_filename(name)
37
47
  File.dirname(__FILE__) + "/fixtures/#{name}"
38
48
  end
@@ -20,6 +20,13 @@ module Roflbot
20
20
  roflbot = Base.new(@options)
21
21
  end
22
22
 
23
+ def test_new_with_gvoice
24
+ conf = stub("gvoice config")
25
+ @options['accounts']['Google Voice'] = conf
26
+ GvoiceRuby::Client.expects(:new).with(conf).returns(@gvoice)
27
+ roflbot = Base.new(@options)
28
+ end
29
+
23
30
  def test_start
24
31
  roflbot = Base.new(@options)
25
32
  @client.expects(:connect)
@@ -99,5 +106,22 @@ module Roflbot
99
106
  @buddy.expects(:send_im).with("omg wtf")
100
107
  receive_im("hey")
101
108
  end
109
+
110
+ def test_respond_via_sms_with_string
111
+ conf = stub("gvoice config")
112
+ @options['accounts']['Google Voice'] = conf
113
+ roflbot = Base.new(@options)
114
+ roflbot.expects(/^hey$/).responds { "omg wtf" }
115
+
116
+ seq = sequence("foo")
117
+ @gvoice.expects(:check).in_sequence(seq)
118
+ @gvoice.expects(:any_unread?).returns(true).in_sequence(seq)
119
+ @gvoice.expects(:smss).returns([fake_sms("hey")]).in_sequence(seq)
120
+ @gvoice.expects(:send_sms).with({
121
+ :phone_number => "+16158675309",
122
+ :text => "omg wtf",
123
+ }).in_sequence(seq)
124
+ roflbot.respond_via_sms
125
+ end
102
126
  end
103
127
  end
@@ -0,0 +1,11 @@
1
+ # A sample Gemfile
2
+ source :gemcutter
3
+ #
4
+ # gem "rails"
5
+ gem 'curb'
6
+ gem 'nokogiri'
7
+ gem 'json'
8
+ gem 'thoughtbot-shoulda'
9
+ gem 'mocha'
10
+ gem 'xmpp4r-simple'
11
+ gem 'bundler'
@@ -0,0 +1,71 @@
1
+ = gvoice-ruby
2
+
3
+ == Introduction
4
+
5
+ gvoice-ruby is a library for interacting with Google's Voice service (previously GrandCentral) using ruby. As Google does not yet publish an official API for Google Voice gvoice-ruby uses the ruby libcurl library (Curb) to interact with the web service itself by using the HTTP verbs POST and GET to send and retrieve information to the Google Voice service.
6
+
7
+ gvoice-ruby is currently a very preliminary project with limited functionality basically confined to returning arrays of voicemail or sms objects and sending sms messages, or connecting calls. It cannot cancel calls already in progress. It currently works under ruby 1.8.7 and 1.9.2-preview1 on my computer running Mac OS X 10.6 (Snow Leopard). It is not guaranteed to work anywhere else and has very few tests.
8
+
9
+ == Prerequisites
10
+
11
+ 1.) The Curb library (gem install curb)
12
+
13
+ 2.) The Nokogiri library (gem install nokogiri)
14
+
15
+ 3.) The JSON library (gem install json)
16
+
17
+ 4.) Possibly setting your RUBYOPT environment variable to the string 'rubygems'.
18
+
19
+ $ RUBYOPT='rubygems'
20
+
21
+ $ echo $RUBYOPT
22
+
23
+ => rubygems
24
+
25
+ == Installing
26
+
27
+ Eventually it will be a gem, but for now:
28
+
29
+ $ git clone git://github.com/kgautreaux/gvoice-ruby.git
30
+
31
+ == Examples
32
+
33
+ Please see the bin/ directory for examples of using the library to accomplish some tasks.
34
+
35
+ == Known Issues
36
+
37
+ The library tries not to require 'rubygems' per http://gist.github.com/54177 and thus works fine on 1.9.2-preview1 but breaks on 1.8.7 unless you invoke any of the scripts with ruby -rubygems [whatever...] or set your RUBYOPT environment variable as noted above.
38
+
39
+ Alternatively you can require 'rubygems' in your own script using the underlying library or set your $RUBYOPT environment variable as outlined in the gist above, but keep this issue in mind.
40
+
41
+ == BUGS
42
+
43
+ 1.) It has few tests.
44
+
45
+ 2.) If the Google Voice service changes in any way it will break.
46
+
47
+ 3.) If the libraries used change it will break.
48
+
49
+ 4.) It is somewhat tightly coupled to the private post and fetch_page methods (sms and voicemail arrays depend upon these methods).
50
+
51
+ 5.) It is not RESTful in any way.
52
+
53
+ 6.) It cannot yet cancel calls, but it can initiate them.
54
+
55
+ 7.) It is my first attempt at writing a library and is not idiomatic ruby.
56
+
57
+ 8.) It requires rubygems but doesn't set RUBYOPT environment variable.
58
+
59
+ 9.) It requires the file compatibility.rb which monkeypatches the Array and Symbol classes on Ruby < 1.9 to enable sorting.
60
+
61
+ 10.) You cannot change any of the Google Voice settings using this library.
62
+
63
+ 11.) The library loads a specific YAML file that must be in place for anything to work as the script has no logical defaults.
64
+
65
+ 12.) Minimal to no error handling present. Fail silent...Fail deep.
66
+
67
+ 13.) The library doesn't post the id of sms messages it sends so they don't get associated with any conversation in Google Voice.
68
+
69
+ == Thanks
70
+
71
+ Thanks to Chad Smith for posting the URL for accessing the Google Voice service as listed on http://posttopic.com/topic/google-voice-add-on-development#post-27
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ desc "Run all tests for this project."
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'lib' << 'test'
8
+ test.pattern = 'test/**/*_test.rb'
9
+ test.verbose = true
10
+ end
11
+
12
+ task :default => :test
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby -W1
2
+ # coding: UTF-8
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'gvoice-ruby'
5
+ require 'xmpp4r-simple'
6
+
7
+ include GvoiceRuby
8
+
9
+ config = GvoiceRuby::Configurator.load_config
10
+
11
+ # Main
12
+ jabber_bot = Jabber::Simple.new(config[:bot_name], config[:bot_password])
13
+
14
+ voicebox = GvoiceRuby::Client.new
15
+
16
+ voicebox.check
17
+
18
+ voicebox.missed.each do |call|
19
+ if DateTime.parse(call.display_start_date_time).yday >= (Time.now.yday - 3)
20
+ puts "You missed a call from #{call.from} on #{call.display_start_date_time}."
21
+ end
22
+ end
23
+ puts "\n"
24
+
25
+ voicebox.received.each do |call|
26
+ if DateTime.parse(call.display_start_date_time).yday >= (Time.now.yday - 1)
27
+ puts "You received a call from #{call.from} on #{call.display_start_date_time}."
28
+ end
29
+ end
30
+ puts "\n"
31
+
32
+ voicebox.placed.each do |call|
33
+ if DateTime.parse(call.display_start_date_time).yday >= (Time.now.yday - 3)
34
+ puts "You placed a call to #{call.from} on #{call.display_start_date_time}."
35
+ end
36
+ end
37
+ puts "\n"
38
+
39
+ if voicebox.any_unread?
40
+ sms_messages = []
41
+ voicemail_messages = []
42
+
43
+ voicebox.smss.each do |t|
44
+ if t.labels.include?('unread')
45
+ sms_messages << "#{t.from} says: '#{t.text}' at #{t.display_start_date_time}\n"
46
+ voicebox.mark_as_read({:id => t.id})
47
+ voicebox.add_note({:id => t.id, :note => "You were notified via gv-notifier at #{Time.now}."})
48
+ # voicebox.star({:id => t.id})
49
+ else
50
+ next
51
+ end
52
+ end
53
+
54
+ voicebox.voicemails.each do |v|
55
+ if v.labels.include?('unread')
56
+ voicemail_messages << "Voicemail from #{v.from} at #{v.display_start_date_time}:\n#{v.transcript}\n"
57
+ voicebox.mark_as_read({:id => v.id})
58
+ else
59
+ next
60
+ end
61
+ end
62
+
63
+ begin
64
+ [sms_messages, voicemail_messages].each do |thing|
65
+ thing.each { |m| jabber_bot.deliver(voicebox.user.email, m, :normal);print m }
66
+ end
67
+ rescue
68
+ raise
69
+ end
70
+ config[:last_message_start_time] = voicebox.all_messages.last.start_time
71
+ else
72
+ print "No unread messages in your Google Voice inbox.\n"
73
+ end
74
+
75
+ GvoiceRuby::Configurator.write_config(config)
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby -W1
2
+ # coding: UTF-8
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'gvoice-ruby'
5
+ include GvoiceRuby
6
+
7
+ voicebox = GvoiceRuby::Client.new
8
+
9
+ # Phone types:
10
+ # 1) Home
11
+ # 2) Mobile
12
+ # 3) Work
13
+ # 7) Gizmo
14
+ this_phone = { :outgoing_number => "3088720071", :forwarding_number => "3088721257", :phone_type => 2 }
15
+
16
+ puts "Call connected!" if voicebox.call(this_phone)
17
+
18
+ puts "Call cancelled!" if voicebox.cancel_call