roflbot 0.0.1 → 0.0.3

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