roflbot 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1 +1 @@
1
- roflbot is an AIM bot.
1
+ roflbot is an bot that says stuff on AIM and Twitter.
data/Rakefile CHANGED
@@ -5,13 +5,14 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "roflbot"
8
- gem.summary = %Q{roflbot is a simple AIM bot}
9
- gem.description = %Q{roflbot is a simple AIM bot, yo}
8
+ gem.summary = %Q{roflbot is a bot that says stuff on AIM and Twitter}
9
+ gem.description = %Q{roflbot will make you a rofl waffle}
10
10
  gem.email = "viking415@gmail.com"
11
11
  gem.homepage = "http://github.com/viking/roflbot"
12
12
  gem.authors = ["Jeremy Stephens"]
13
13
  gem.add_dependency "net-toc"
14
14
  gem.add_dependency "treetop"
15
+ gem.add_dependency "twitter"
15
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
17
  end
17
18
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.3
@@ -4,6 +4,7 @@ require 'yaml'
4
4
  require 'rubygems'
5
5
  require 'net/toc'
6
6
  require 'treetop'
7
+ require 'twitter'
7
8
 
8
9
  module Roflbot
9
10
  end
@@ -21,19 +21,38 @@ module Roflbot
21
21
  end
22
22
 
23
23
  extend Forwardable
24
- def initialize(username, password, options = {})
25
- @username = username
26
- @password = password
24
+ TWITTER = { :token => "7rfuoIhSGN7OQVvDLzJrcg", :secret => "I2o4SmRWVV4Yo7XhGgLrKGJq1KgpC8VrluyA9LLuH0" }
25
+
26
+ attr_reader :options
27
+ def initialize(options = {})
27
28
  @options = options
28
29
  @expectations = []
30
+ accounts = @options["accounts"]
31
+
32
+ @aim = Net::TOC.new(*accounts["AIM"].values_at("username", "password"))
33
+ @aim.on_im { |m, b, a| on_im(m, b, a) }
34
+
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
29
40
 
30
- @client = Net::TOC.new(@username, @password)
31
- @client.on_im { |m, b, a| on_im(m, b, a) }
41
+ def_delegator :@aim, :disconnect
42
+
43
+ def start
44
+ @aim.connect
45
+ @thread = Thread.new { loop { respond_via_twitter; sleep 60 } }
46
+ end
47
+
48
+ def wait
49
+ @aim.wait
32
50
  end
33
51
 
34
- def_delegator :@client, :connect
35
- def_delegator :@client, :disconnect
36
- def_delegator :@client, :wait
52
+ def stop
53
+ @aim.disconnect
54
+ @thread.kill if @thread
55
+ end
37
56
 
38
57
  def expects(regexp)
39
58
  exp = Expectation.new(regexp)
@@ -53,5 +72,29 @@ module Roflbot
53
72
  break
54
73
  end
55
74
  end
75
+
76
+ def respond_via_twitter
77
+ mentions = @twitter.mentions(@since_id ? {:since_id => @since_id} : {})
78
+ if !mentions.empty?
79
+ @since_id = mentions[-1].id
80
+ @options['accounts']['Twitter']['since_id'] = @since_id
81
+ end
82
+
83
+ mentions.each do |tweet|
84
+ @expectations.each do |expectation|
85
+ # throw away beginning mention
86
+ message = tweet.text.sub(/^@[^\s]+\s+/, "")
87
+
88
+ next if !expectation.matches?(message)
89
+ case expectation.response
90
+ when Proc
91
+ @twitter.update("@#{tweet.user.screen_name} #{expectation.response.call}")
92
+ when String
93
+ @twitter.update("@#{tweet.user.screen_name} #{expectation.response}")
94
+ end
95
+ break
96
+ end
97
+ end
98
+ end
56
99
  end
57
100
  end
@@ -1,19 +1,20 @@
1
1
  module Roflbot
2
2
  class Runner
3
3
  def initialize(argv = ARGV)
4
- username = nil
5
- password = nil
6
- options = {}
4
+ @config = nil
7
5
  OptionParser.new do |opts|
8
- opts.on("-u", "--username USERNAME") { |u| username = u }
9
- opts.on("-p", "--password PASSWORD") { |p| password = p }
10
- opts.on("-c", "--config FILENAME") { |c| options = YAML.load_file(c) }
6
+ opts.on("-c", "--config FILENAME") { |c| @config = c }
11
7
  end.parse!(argv)
12
8
 
13
- bot = SentenceBot.new(username, password, options)
14
- bot.connect
15
- Signal.trap("INT") { bot.disconnect }
16
- bot.wait
9
+ @bot = SentenceBot.new(YAML.load_file(@config))
10
+ Signal.trap("INT") { stop }
11
+ @bot.start
12
+ @bot.wait
13
+ end
14
+
15
+ def stop
16
+ @bot.stop
17
+ File.open(@config, "w") { |f| f.write(@bot.options.to_yaml) }
17
18
  end
18
19
  end
19
20
  end
@@ -6,7 +6,7 @@ module Roflbot
6
6
  super
7
7
  parser = SentenceParser.new
8
8
  @sentences = []
9
- @options.delete("sentences").each do |sentence|
9
+ @options["sentences"].each do |sentence|
10
10
  node = parser.parse(sentence)
11
11
  @sentences << node
12
12
  end
@@ -5,13 +5,13 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{roflbot}
8
- s.version = "0.0.1"
8
+ s.version = "0.0.3"
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
12
  s.date = %q{2010-06-30}
13
13
  s.default_executable = %q{roflbot}
14
- s.description = %q{roflbot is a simple AIM bot, yo}
14
+ s.description = %q{roflbot will make you a rofl waffle}
15
15
  s.email = %q{viking415@gmail.com}
16
16
  s.executables = ["roflbot"]
17
17
  s.extra_rdoc_files = [
@@ -41,7 +41,7 @@ Gem::Specification.new do |s|
41
41
  s.rdoc_options = ["--charset=UTF-8"]
42
42
  s.require_paths = ["lib"]
43
43
  s.rubygems_version = %q{1.3.6}
44
- s.summary = %q{roflbot is a simple AIM bot}
44
+ s.summary = %q{roflbot is a bot that says stuff on AIM and Twitter}
45
45
  s.test_files = [
46
46
  "test/helper.rb",
47
47
  "test/roflbot/test_sentence_bot.rb",
@@ -56,13 +56,16 @@ Gem::Specification.new do |s|
56
56
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
57
  s.add_runtime_dependency(%q<net-toc>, [">= 0"])
58
58
  s.add_runtime_dependency(%q<treetop>, [">= 0"])
59
+ s.add_runtime_dependency(%q<twitter>, [">= 0"])
59
60
  else
60
61
  s.add_dependency(%q<net-toc>, [">= 0"])
61
62
  s.add_dependency(%q<treetop>, [">= 0"])
63
+ s.add_dependency(%q<twitter>, [">= 0"])
62
64
  end
63
65
  else
64
66
  s.add_dependency(%q<net-toc>, [">= 0"])
65
67
  s.add_dependency(%q<treetop>, [">= 0"])
68
+ s.add_dependency(%q<twitter>, [">= 0"])
66
69
  end
67
70
  end
68
71
 
@@ -3,6 +3,7 @@ require 'rubygems'
3
3
  require 'mocha'
4
4
  require 'delegate'
5
5
  require 'ruby-debug'
6
+ require 'tempfile'
6
7
  require File.dirname(__FILE__) + "/../lib/roflbot"
7
8
 
8
9
  class FakeClient < Mocha::Mock
@@ -17,13 +18,31 @@ class Test::Unit::TestCase
17
18
  @client = FakeClient.new
18
19
  @buddy = stub("Buddy")
19
20
  Net::TOC.stubs(:new).returns(@client)
21
+
22
+ @oauth = stub("OAuth", :authorize_from_access => [])
23
+ @twitter = stub("Twitter", :mentions => [])
24
+ Twitter::OAuth.stubs(:new).returns(@oauth)
25
+ Twitter::Base.stubs(:new).returns(@twitter)
20
26
  end
21
27
 
22
28
  def receive_im(message, auto = false)
23
29
  @client.on_im_block.call(message, @buddy, auto)
24
30
  end
25
31
 
32
+ def fake_tweet(message, id)
33
+ Hashie::Mash.new("user" => { "screen_name" => "dudeguy" }, "text" => "@roflbot #{message}", "id" => id)
34
+ end
35
+
26
36
  def fixture_filename(name)
27
37
  File.dirname(__FILE__) + "/fixtures/#{name}"
28
38
  end
39
+
40
+ def create_config(name)
41
+ tmp = Tempfile.open("roflbot_config")
42
+ file = File.open(fixture_filename(name), "r")
43
+ tmp.write(file.read)
44
+ file.close
45
+ tmp.close
46
+ tmp.path
47
+ end
29
48
  end
@@ -2,39 +2,90 @@ require File.dirname(__FILE__) + "/../helper"
2
2
 
3
3
  module Roflbot
4
4
  class TestBase < Test::Unit::TestCase
5
+ def setup
6
+ super
7
+ @options = {
8
+ "accounts" => {
9
+ "AIM" => { "username" => "roflbot", "password" => "password" },
10
+ "Twitter" => { "token" => "abcdef", "secret" => "123456" }
11
+ }
12
+ }
13
+ end
14
+
5
15
  def test_new
6
16
  Net::TOC.expects(:new).with("roflbot", "password").returns(@client)
7
- roflbot = Base.new("roflbot", "password")
17
+ Twitter::OAuth.expects(:new).with(Base::TWITTER[:token], Base::TWITTER[:secret]).returns(@oauth)
18
+ @oauth.expects(:authorize_from_access).with("abcdef", "123456")
19
+ Twitter::Base.expects(:new).with(@oauth).returns(@twitter)
20
+ roflbot = Base.new(@options)
8
21
  end
9
22
 
10
- def test_connect
11
- roflbot = Base.new("roflbot", "password")
23
+ def test_start
24
+ roflbot = Base.new(@options)
12
25
  @client.expects(:connect)
13
- roflbot.connect
26
+ roflbot.start
14
27
  end
15
28
 
16
29
  def test_wait
17
- roflbot = Base.new("roflbot", "password")
30
+ roflbot = Base.new(@options)
18
31
  @client.expects(:wait)
19
32
  roflbot.wait
20
33
  end
21
34
 
22
- def test_disconnect
23
- roflbot = Base.new("roflbot", "password")
35
+ def test_stop
36
+ roflbot = Base.new(@options)
24
37
  @client.expects(:disconnect)
25
- roflbot.disconnect
38
+ roflbot.stop
26
39
  end
27
40
 
28
- def test_responds_with_string
29
- roflbot = Base.new("roflbot", "password")
41
+ def test_responds_to_aim_with_string
42
+ roflbot = Base.new(@options)
30
43
  roflbot.expects(/^hey$/).responds("oh hai")
31
44
 
32
45
  @buddy.expects(:send_im).with("oh hai")
33
46
  receive_im("hey")
34
47
  end
35
48
 
36
- def test_responds_with_block
37
- roflbot = Base.new("roflbot", "password")
49
+ def test_responds_to_twitter_with_string
50
+ roflbot = Base.new(@options)
51
+ roflbot.expects(/^hey$/).responds("oh hai")
52
+
53
+ seq = sequence("foo")
54
+ @twitter.expects(:mentions).returns([fake_tweet("hey", 12345)]).in_sequence(seq)
55
+ @twitter.expects(:update).with("@dudeguy oh hai").in_sequence(seq)
56
+ roflbot.respond_via_twitter
57
+
58
+ seq = sequence("bar")
59
+ @twitter.expects(:mentions).with(:since_id => 12345).returns([fake_tweet("hey", 23456)]).in_sequence(seq)
60
+ @twitter.expects(:update).with("@dudeguy oh hai").in_sequence(seq)
61
+ roflbot.respond_via_twitter
62
+ end
63
+
64
+ def test_saves_since_id
65
+ roflbot = Base.new(@options)
66
+ roflbot.expects(/^hey$/).responds("oh hai")
67
+
68
+ seq = sequence("foo")
69
+ @twitter.expects(:mentions).returns([fake_tweet("hey", 12345)]).in_sequence(seq)
70
+ @twitter.expects(:update).with("@dudeguy oh hai").in_sequence(seq)
71
+ roflbot.respond_via_twitter
72
+
73
+ assert_equal 12345, roflbot.options['accounts']['Twitter']['since_id']
74
+ end
75
+
76
+ def test_uses_saved_since_id
77
+ @options['accounts']['Twitter']['since_id'] = 1337
78
+ roflbot = Base.new(@options)
79
+ roflbot.expects(/^hey$/).responds("oh hai")
80
+
81
+ seq = sequence("foo")
82
+ @twitter.expects(:mentions).with(:since_id => 1337).returns([fake_tweet("hey", 12345)]).in_sequence(seq)
83
+ @twitter.expects(:update).with("@dudeguy oh hai").in_sequence(seq)
84
+ roflbot.respond_via_twitter
85
+ end
86
+
87
+ def test_responds_to_aim_with_block
88
+ roflbot = Base.new(@options)
38
89
  roflbot.expects(/^hey$/).responds { "omg wtf" }
39
90
 
40
91
  @buddy.expects(:send_im).with("omg wtf")
@@ -2,10 +2,29 @@ require File.dirname(__FILE__) + "/../helper"
2
2
 
3
3
  module Roflbot
4
4
  class TestRunner < Test::Unit::TestCase
5
+ def setup
6
+ super
7
+ @bot = stub("SentenceBot", :start => nil, :wait => nil, :options => {})
8
+ SentenceBot.stubs(:new).returns(@bot)
9
+ end
10
+
5
11
  def test_runs_sentence_bot
6
- bot = mock("SentenceBot", :connect => nil, :wait => nil)
7
- SentenceBot.expects(:new).with("foo", "bar", { "foo" => "bar" }).returns(bot)
8
- Runner.new(%W{-u foo -p bar -c #{fixture_filename("bogus.yml")}})
12
+ @bot.expects(:start)
13
+ @bot.expects(:wait)
14
+ SentenceBot.expects(:new).with({ "foo" => "bar" }).returns(@bot)
15
+ Runner.new(%W{-c #{create_config("bogus.yml")}})
16
+ end
17
+
18
+ def test_stop
19
+ config = create_config("bogus.yml")
20
+ runner = Runner.new(%W{-c #{config}})
21
+ @bot.stubs(:options).returns({ "omg" => "whoa" })
22
+
23
+ @bot.expects(:stop)
24
+ runner.stop
25
+
26
+ hash = YAML.load_file(config)
27
+ assert_equal({ "omg" => "whoa" }, hash)
9
28
  end
10
29
  end
11
30
  end
@@ -2,16 +2,25 @@ require File.dirname(__FILE__) + "/../helper"
2
2
 
3
3
  module Roflbot
4
4
  class TestSentenceBot < Test::Unit::TestCase
5
+ def setup
6
+ super
7
+ @options = {
8
+ "accounts" => {
9
+ "AIM" => {"username" => 'dudeguy', "password" => 'password'},
10
+ "Twitter" => { "token" => "abcdef", "secret" => "123456" }
11
+ },
12
+ "sentences" => ["Hey (noun), (ending)"],
13
+ "noun" => %w{dude guy},
14
+ "ending" => ["sup?", "I love you."]
15
+ }
16
+ end
17
+
5
18
  def test_base_superclass
6
19
  assert_equal Base, SentenceBot.superclass
7
20
  end
8
21
 
9
22
  def test_responses
10
- bot = SentenceBot.new('dudeguy', 'password', {
11
- "sentences" => ["Hey (noun), (ending)"],
12
- "noun" => %w{dude guy},
13
- "ending" => ["sup?", "I love you."]
14
- })
23
+ bot = SentenceBot.new(@options)
15
24
 
16
25
  @buddy.expects(:send_im).times(100).with do |message|
17
26
  message =~ /^Hey (dude|guy), (sup\?|I love you.)$/
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeremy Stephens
@@ -41,7 +41,19 @@ dependencies:
41
41
  version: "0"
42
42
  type: :runtime
43
43
  version_requirements: *id002
44
- description: roflbot is a simple AIM bot, yo
44
+ - !ruby/object:Gem::Dependency
45
+ name: twitter
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ type: :runtime
55
+ version_requirements: *id003
56
+ description: roflbot will make you a rofl waffle
45
57
  email: viking415@gmail.com
46
58
  executables:
47
59
  - roflbot
@@ -97,7 +109,7 @@ rubyforge_project:
97
109
  rubygems_version: 1.3.6
98
110
  signing_key:
99
111
  specification_version: 3
100
- summary: roflbot is a simple AIM bot
112
+ summary: roflbot is a bot that says stuff on AIM and Twitter
101
113
  test_files:
102
114
  - test/helper.rb
103
115
  - test/roflbot/test_sentence_bot.rb