campfire-bot 0.0.1

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.
Files changed (115) hide show
  1. data/.autotest +11 -0
  2. data/.gitignore +6 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +57 -0
  5. data/README.textile +52 -0
  6. data/TODO +72 -0
  7. data/bin/bot +13 -0
  8. data/campfire-bot.gemspec +27 -0
  9. data/cfbot-stop.sh +8 -0
  10. data/config.example.yml +31 -0
  11. data/lib/bot.rb +194 -0
  12. data/lib/event.rb +114 -0
  13. data/lib/message.rb +30 -0
  14. data/lib/plugin.rb +77 -0
  15. data/lib/version.rb +3 -0
  16. data/plugins/accountability.rb +45 -0
  17. data/plugins/austin.rb +29 -0
  18. data/plugins/basecamp.rb +48 -0
  19. data/plugins/beer.rb +214 -0
  20. data/plugins/beijing_tally.rb +30 -0
  21. data/plugins/boop.rb +127 -0
  22. data/plugins/bruce.rb +15 -0
  23. data/plugins/bugzilla.rb +198 -0
  24. data/plugins/calvin.rb +43 -0
  25. data/plugins/chuck.rb +23 -0
  26. data/plugins/dilbert.rb +51 -0
  27. data/plugins/excuse.rb +478 -0
  28. data/plugins/fail.rb +16 -0
  29. data/plugins/figlet.rb +10 -0
  30. data/plugins/fun.rb +95 -0
  31. data/plugins/garfield.rb +43 -0
  32. data/plugins/generic_search.rb +66 -0
  33. data/plugins/help.rb +13 -0
  34. data/plugins/infobot.rb +58 -0
  35. data/plugins/insult.rb +87 -0
  36. data/plugins/jira.rb +197 -0
  37. data/plugins/lolcats.rb +17 -0
  38. data/plugins/our_quotes.rb +195 -0
  39. data/plugins/quote.rb +31 -0
  40. data/plugins/schneier.rb +28 -0
  41. data/plugins/seen.rb +88 -0
  42. data/plugins/signal_filter.rb +9 -0
  43. data/plugins/svn.rb +167 -0
  44. data/plugins/twitter_echo.rb +54 -0
  45. data/plugins/unfuddle.rb +69 -0
  46. data/plugins/weather.rb +25 -0
  47. data/plugins/xkcd.rb +43 -0
  48. data/spec/beer_spec.rb +224 -0
  49. data/spec/bugzilla_spec.rb +90 -0
  50. data/spec/command_spec.rb +96 -0
  51. data/spec/jira_spec.rb +264 -0
  52. data/spec/our_quotes_spec.rb +186 -0
  53. data/spec/plugin_spec.rb +43 -0
  54. data/spec/spec.opts +1 -0
  55. data/vendor/escape/ChangeLog +30 -0
  56. data/vendor/escape/Makefile +5 -0
  57. data/vendor/escape/README +81 -0
  58. data/vendor/escape/VERSION +1 -0
  59. data/vendor/escape/escape.rb +302 -0
  60. data/vendor/escape/install.rb +109 -0
  61. data/vendor/escape/misc/README.erb +85 -0
  62. data/vendor/escape/rdoc/classes/Escape.html +427 -0
  63. data/vendor/escape/rdoc/classes/Escape.src/M000022.html +19 -0
  64. data/vendor/escape/rdoc/classes/Escape.src/M000023.html +32 -0
  65. data/vendor/escape/rdoc/classes/Escape.src/M000024.html +24 -0
  66. data/vendor/escape/rdoc/classes/Escape.src/M000025.html +19 -0
  67. data/vendor/escape/rdoc/classes/Escape.src/M000026.html +48 -0
  68. data/vendor/escape/rdoc/classes/Escape.src/M000027.html +19 -0
  69. data/vendor/escape/rdoc/classes/Escape.src/M000028.html +19 -0
  70. data/vendor/escape/rdoc/classes/Escape/HTMLAttrValue.html +113 -0
  71. data/vendor/escape/rdoc/classes/Escape/HTMLEscaped.html +113 -0
  72. data/vendor/escape/rdoc/classes/Escape/PercentEncoded.html +113 -0
  73. data/vendor/escape/rdoc/classes/Escape/ShellEscaped.html +113 -0
  74. data/vendor/escape/rdoc/classes/Escape/StringWrapper.html +242 -0
  75. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000029.html +18 -0
  76. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000030.html +18 -0
  77. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000031.html +18 -0
  78. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000032.html +18 -0
  79. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000033.html +18 -0
  80. data/vendor/escape/rdoc/classes/Escape/StringWrapper.src/M000035.html +18 -0
  81. data/vendor/escape/rdoc/classes/TestEscapeHTML.html +182 -0
  82. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000008.html +18 -0
  83. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000009.html +18 -0
  84. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000010.html +18 -0
  85. data/vendor/escape/rdoc/classes/TestEscapeHTML.src/M000011.html +18 -0
  86. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.html +182 -0
  87. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000012.html +18 -0
  88. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000013.html +19 -0
  89. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000014.html +20 -0
  90. data/vendor/escape/rdoc/classes/TestEscapePercentEncoded.src/M000015.html +22 -0
  91. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.html +167 -0
  92. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000016.html +18 -0
  93. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000017.html +20 -0
  94. data/vendor/escape/rdoc/classes/TestEscapeShellEscaped.src/M000018.html +20 -0
  95. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.html +167 -0
  96. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000019.html +20 -0
  97. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000020.html +24 -0
  98. data/vendor/escape/rdoc/classes/TestEscapeStringWrapper.src/M000021.html +22 -0
  99. data/vendor/escape/rdoc/files/escape_rb.html +136 -0
  100. data/vendor/escape/rdoc/files/install_rb.html +250 -0
  101. data/vendor/escape/rdoc/files/install_rb.src/M000001.html +23 -0
  102. data/vendor/escape/rdoc/files/install_rb.src/M000002.html +31 -0
  103. data/vendor/escape/rdoc/files/install_rb.src/M000003.html +27 -0
  104. data/vendor/escape/rdoc/files/install_rb.src/M000004.html +27 -0
  105. data/vendor/escape/rdoc/files/install_rb.src/M000005.html +21 -0
  106. data/vendor/escape/rdoc/files/install_rb.src/M000006.html +23 -0
  107. data/vendor/escape/rdoc/files/install_rb.src/M000007.html +21 -0
  108. data/vendor/escape/rdoc/files/test/test-escape_rb.html +109 -0
  109. data/vendor/escape/rdoc/fr_class_index.html +36 -0
  110. data/vendor/escape/rdoc/fr_file_index.html +29 -0
  111. data/vendor/escape/rdoc/fr_method_index.html +61 -0
  112. data/vendor/escape/rdoc/index.html +24 -0
  113. data/vendor/escape/rdoc/rdoc-style.css +208 -0
  114. data/vendor/escape/test/test-escape.rb +90 -0
  115. metadata +259 -0
@@ -0,0 +1,96 @@
1
+ require 'spec'
2
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
3
+ BOT_ENVIRONMENT = 'development'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
6
+ bot = CampfireBot::Bot.instance
7
+ require "#{BOT_ROOT}/lib/event.rb"
8
+
9
+
10
+ class TestingCommand < CampfireBot::Event::Command
11
+
12
+ def filter_message(msg)
13
+ super
14
+ end
15
+ end
16
+
17
+ describe "processing messages" do
18
+
19
+ before(:all) do
20
+ bot = CampfireBot::Bot.instance
21
+ @nickname = bot.config['nickname']
22
+ end
23
+
24
+ before(:each) do
25
+ @command = TestingCommand.new("command", nil, nil)
26
+ end
27
+
28
+ def match?(msg)
29
+ @command.match?({:message => msg})
30
+ end
31
+
32
+ describe "and recognizing a command" do
33
+
34
+ it "should handle a !command" do
35
+ match?("!command").should be_true
36
+ end
37
+
38
+ it "should handle a !command with arguments" do
39
+ match?("!command foo").should be_true
40
+ end
41
+
42
+ it "should handle a command with nickname and a comma" do
43
+ match?("#{@nickname}, command").should be_true
44
+ end
45
+
46
+ it "should handle a command with nickname and a colon" do
47
+ match?("#{@nickname}: command").should be_true
48
+ end
49
+
50
+ it "should handle a command with nickname and arguments" do
51
+ match?("#{@nickname}, command foo").should be_true
52
+ end
53
+
54
+ it "should ignore a non-matching !command" do
55
+ match?("!foo").should be_false
56
+ end
57
+
58
+ it "should ignore an addressed non-command" do
59
+ match?("#{@nickname}, nothing").should be_false
60
+ end
61
+
62
+ it "should ignore things that aren't commands at all" do
63
+ ["nothing", "#{@nickname}, ", " ! command", "hey #{@nickname}", "!command!command", "!command,command"].each do |t|
64
+ match?(t).should be_false
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "and filtering it" do
70
+
71
+ def filter(msg)
72
+ @command.filter_message({:message => msg})[:message]
73
+ end
74
+
75
+ it "should be empty with no arguments" do
76
+ filter("!command").should == ""
77
+ filter("#{@nickname}, command").should == ""
78
+ end
79
+
80
+ it "should return one argument" do
81
+ filter("!command foo").should == "foo"
82
+ filter("#{@nickname}, command foo").should == "foo"
83
+ end
84
+
85
+ it "should return more than one argument" do
86
+ filter("!command foo bar baz").should == "foo bar baz"
87
+ filter("#{@nickname}, command foo bar baz").should == "foo bar baz"
88
+ end
89
+
90
+ it "should deal with some weirdness" do
91
+ filter("!command !command").should == "!command"
92
+ end
93
+
94
+ end
95
+ end
96
+
@@ -0,0 +1,264 @@
1
+ require 'spec'
2
+ require 'rubygems'
3
+ require 'xmlsimple'
4
+
5
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
6
+ BOT_ENVIRONMENT = 'development'
7
+
8
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
9
+ bot = CampfireBot::Bot.instance
10
+ require "#{BOT_ROOT}/plugins/jira.rb"
11
+
12
+
13
+ class SpecMessage < CampfireBot::Message
14
+ attr_reader :response
15
+
16
+ #overwrite message.speak method so that we can expose the output
17
+ def speak(msg)
18
+ puts "specmessage.speak(#{msg})"
19
+ @response = msg
20
+ end
21
+
22
+ end
23
+
24
+ class SpecJira < CampfireBot::Plugin::Jira
25
+ attr_accessor :cached_ids, :last_checked
26
+ end
27
+
28
+
29
+
30
+ describe "checking jira and" do
31
+
32
+
33
+ # send a message to the room and return the response
34
+ def sendmsg(msg)
35
+ # puts "sendmsg(#{msg})"
36
+ @message[:message] = msg
37
+ @message[:room] = mock('room', :name => 'test')
38
+ bot.send(:handle_message, @message)
39
+ # puts "sendmsg returns #{@message.response}"
40
+ @message.response
41
+ end
42
+
43
+ # instantiate the bot and the plugin fresh
44
+
45
+ def setup
46
+ bot = CampfireBot::Bot.instance
47
+ bot.stub!(:config).and_return({'nickname' => 'Bot', 'jira_url' => 'foo'})
48
+ YAML.stub!(:load).and_return {}
49
+ YAML.stub!(:dump).and_return true
50
+
51
+
52
+
53
+ @jira = SpecJira.new()
54
+ CampfireBot::Plugin.registered_plugins['Jira'] = @jira
55
+ @jira.cached_ids = {}
56
+ @jira.last_checked = 15.minutes.ago
57
+ @message = nil
58
+ end
59
+
60
+ def jira_response(ticketarray)
61
+
62
+ jira_hash = {'rss' => {'channel' => [] }}
63
+
64
+ ticketarray.each do |ticket|
65
+ ticket.merge!({'description' => 'foo',
66
+ 'link' => "http://oz/jira/browse/#{ticket['key']}",
67
+ 'title' => 'foo',
68
+ 'reporter' => 'foo',
69
+ 'priority' => 'Critical',
70
+ 'type' => 'Bug'})
71
+
72
+ jira_hash['rss']['channel'] << {'item' => ticket }
73
+ end
74
+
75
+ @message = SpecMessage.new(:person => 'Josh', :room => mock('room', :name => 'test'))
76
+
77
+ xmldata = XmlSimple.xml_out(jira_hash, {'NoAttr' => true, 'RootName' => nil})
78
+
79
+ @jira.stub!(:open).and_return(mock('foo', :read => xmldata))
80
+
81
+ @jira.check_jira(@message)
82
+ end
83
+
84
+ describe "seeing a ticket higher than the last stored id" do
85
+
86
+ before(:all) do
87
+ setup
88
+ jira_response([{
89
+ 'key' => 'PIM-123',
90
+ 'description' => 'foo',
91
+ 'link' => 'http://oz/jira/browse/PIM-123',
92
+ 'title' => 'foo',
93
+ 'reporter' => 'foo',
94
+ 'priority' => 'Critical',
95
+ 'type' => 'Bug',
96
+ 'updated' => 5.minutes.ago.to_s
97
+ }])
98
+
99
+ @jira.last_checked = 5.minutes.ago
100
+ jira_response([{
101
+ 'key' => 'PIM-124',
102
+ 'description' => 'foo',
103
+ 'link' => 'http://oz/jira/browse/PIM-124',
104
+ 'title' => 'foo',
105
+ 'reporter' => 'foo',
106
+ 'priority' => 'Critical',
107
+ 'type' => 'Bug',
108
+ 'updated' => 3.minutes.ago.to_s
109
+ }])
110
+ end
111
+
112
+ it "should update the cached highest id" do
113
+ @jira.cached_ids['PIM'].should eql(124)
114
+ end
115
+
116
+ it "should speak the info of the ticket" do
117
+ @message.response.should match(/PIM-124/)
118
+ end
119
+
120
+
121
+ end
122
+
123
+ describe "seeing a ticket we've already seen" do
124
+
125
+ before(:all) do
126
+ setup
127
+ jira_response([{
128
+ 'key' => 'PIM-123',
129
+
130
+ 'updated' => Time.now().to_s
131
+ }])
132
+
133
+ jira_response([{
134
+ 'key' => 'PIM-123',
135
+ 'description' => 'foo',
136
+ 'link' => 'http://oz/jira/browse/PIM-123',
137
+ 'title' => 'foo',
138
+ 'reporter' => 'foo',
139
+ 'priority' => 'Critical',
140
+ 'type' => 'Bug',
141
+ 'updated' => Time.now().to_s
142
+ }])
143
+ end
144
+
145
+ it "should be quiet" do
146
+ @message.response.should be(nil)
147
+ end
148
+
149
+ it "should not change the list of cached ids" do
150
+ @jira.cached_ids.size.should eql(1)
151
+ end
152
+
153
+
154
+ end
155
+
156
+ describe "seeing a ticket whose ID is lower than the highest seen id" do
157
+ before(:all) do
158
+ setup
159
+ jira_response([{
160
+ 'key' => 'PIM-123',
161
+ 'updated' => 5.minutes.ago.to_s
162
+ }])
163
+
164
+ @jira.last_checked = 3.minutes.ago
165
+
166
+ jira_response([{
167
+ 'key' => 'PIM-120',
168
+ 'updated' => Time.now().to_s
169
+ }])
170
+
171
+ end
172
+
173
+ it "should be quiet" do
174
+ @message.response.should be(nil)
175
+ end
176
+
177
+ end
178
+
179
+ describe "seeing a space we've never seen before" do
180
+ before(:all) do
181
+ setup
182
+ jira_response([{
183
+ 'key' => 'PIM-123',
184
+ 'updated' => 5.minutes.ago.to_s
185
+ }])
186
+
187
+ @jira.last_checked = 5.minutes.ago
188
+ jira_response([{
189
+ 'key' => 'FOO-124',
190
+ 'updated' => 3.minutes.ago.to_s
191
+ }])
192
+ end
193
+
194
+ it "should update the cached highest id" do
195
+ @jira.cached_ids['FOO'].should eql(124)
196
+ end
197
+
198
+ it "should speak the info of the ticket" do
199
+ @message.response.should match(/FOO-124/)
200
+ end
201
+ end
202
+
203
+ describe "getting a bunch of tickets in one go" do
204
+ before(:all) do
205
+ setup
206
+ end
207
+
208
+ it "with all new" do
209
+ @jira.cached_ids = {}
210
+
211
+ msg = SpecMessage.new(:person => 'Josh', :room => mock('room', :name => 'test'))
212
+ SpecMessage.should_receive(:new).and_return(msg)
213
+ msg.should_receive(:speak).twice
214
+
215
+ jira_response([{
216
+ 'key' => 'PIM-1124',
217
+ 'updated' => 5.minutes.ago.to_s
218
+ },
219
+ {'key' => 'PIM-1123',
220
+ 'updated' => 5.minutes.ago.to_s}])
221
+ @jira.cached_ids['PIM'].should eql(1124)
222
+
223
+ end
224
+
225
+ it "with a mix of old and new" do
226
+ msg = SpecMessage.new(:person => 'Josh', :room => mock('room', :name => 'test'))
227
+ SpecMessage.should_receive(:new).and_return(msg)
228
+ msg.should_receive(:speak).twice
229
+
230
+ @jira.cached_ids['PIM'] = 1124
231
+ jira_response([{
232
+ 'key' => 'PIM-1126',
233
+ 'updated' => 5.minutes.ago.to_s
234
+ },
235
+ {
236
+ 'key' => 'PIM-1125',
237
+ 'updated' => 5.minutes.ago.to_s
238
+ },
239
+ {
240
+ 'key' => 'PIM-1124',
241
+ 'updated' => 5.minutes.ago.to_s
242
+ }
243
+ ])
244
+ @jira.cached_ids['PIM'].should eql(1126)
245
+ end
246
+
247
+ it "with all old" do
248
+ @jira.cached_ids['PIM'] = 1125
249
+ jira_response([{
250
+ 'key' => 'PIM-1125',
251
+ 'updated' => 5.minutes.ago.to_s
252
+ },
253
+ {'key' => 'PIM-1124',
254
+ 'updated' => 5.minutes.ago.to_s}])
255
+ @jira.cached_ids['PIM'].should eql(1125)
256
+ end
257
+
258
+
259
+
260
+
261
+ end
262
+
263
+ end
264
+
@@ -0,0 +1,186 @@
1
+ require 'spec'
2
+ BOT_ROOT = File.join(File.dirname(__FILE__), '..')
3
+ BOT_ENVIRONMENT = 'test'
4
+
5
+ require File.join(File.dirname(__FILE__), '../lib/bot.rb')
6
+ bot = CampfireBot::Bot.instance
7
+ require "#{BOT_ROOT}/plugins/our_quotes.rb"
8
+
9
+ describe "OurQuotes plugin" do
10
+
11
+ it "should remember added quotes" do
12
+ when_saying "!addquote Someone: Hello world."
13
+ bot_should_reply "Added quote #1."
14
+ quotes[0].should == "Someone: Hello world."
15
+ end
16
+
17
+ it "should complain when !addquote is given without a quote" do
18
+ when_saying "!addquote"
19
+ bot_should_reply "Please include the text of the quote and attribution."
20
+ quotes.size.should == 0
21
+ end
22
+
23
+ it "should regurgitate random quotes" do
24
+ with_quote_log {
25
+ add "Someone: Hello world."
26
+ }
27
+ when_saying "!quote"
28
+ # How to show attribution, index, room, and timestamp?
29
+ #bot_should_reply "Someone spake thusly: Hello world"
30
+ # "Foo quoth thither
31
+ bot_should_reply "#1 Someone: Hello world."
32
+ end
33
+
34
+ it "should find matching quotes" do
35
+ with_quote_log {
36
+ add "Anyone: Hello world."
37
+ add "Someone: Hello world."
38
+ del 1
39
+ add "Someone: It's too cold."
40
+ }
41
+ when_saying "!quote o w"
42
+ bot_should_reply "#2 Someone: Hello world. (1 match)"
43
+ end
44
+
45
+ it "should use proper grammer when showing number of matches" do
46
+ with_quote_log {
47
+ add "Anyone: hi!"
48
+ add "Anyone: bye."
49
+ }
50
+ when_saying "!quote Anyone"
51
+ bot_should_reply %r/ \(2 matches\)$/
52
+ end
53
+
54
+ it "should retrieve quotes by ID when the query is numeric" do
55
+ with_quote_log {
56
+ add "Anyone: 2+2"
57
+ add "Anyone: hi!"
58
+ }
59
+ when_saying "!quote 2"
60
+ bot_should_reply "#2 Anyone: hi!"
61
+ end
62
+
63
+ it "should display an explanation when !quote is given an invalid ID" do
64
+ when_saying "!quote 1"
65
+ bot_should_reply "No quote #1."
66
+ end
67
+
68
+ # Implementation idea: save array of matches in a hash
69
+ # keyed by query and perhaps user. Should expire after
70
+ # a few minutes, so don't bother persisting it even to tmp/.
71
+ it "should iterate through results on repeat command" do
72
+ pending
73
+ with_quote_log {
74
+ add "Someone: Foo"
75
+ add "Someone: Bar"
76
+ add "Someone: Baz"
77
+ }
78
+ when_saying "!quote Someone"
79
+ bot_should_reply %r/#\d Someone: ... \(3 matches\)$/
80
+ when_saying "!quote Someone"
81
+ bot_should_reply %r/#\d Someone: ... \(2 of 3 matches\)$/
82
+ when_saying "!quote Someone"
83
+ bot_should_reply %r/#\d Someone: ... \(3 of 3 matches\)$/
84
+ # Or maybe (3 matches, none left) ?
85
+ end
86
+
87
+ it "should remove last quote upon request" do
88
+ with_quote_log {
89
+ add "Hello world."
90
+ }
91
+ when_saying "!rmquote 1"
92
+ bot_should_reply "Deleted quote #1."
93
+ @quote.quotes.size.should == 0
94
+ end
95
+
96
+ it "should free trailing IDs when removing quotes" do
97
+ with_quote_log {
98
+ add "One"
99
+ add "Two"
100
+ add "Three"
101
+ add "Four"
102
+ del 3
103
+ del 4
104
+ add "III"
105
+ }
106
+ quotes[3 - 1].should == "III"
107
+ end
108
+
109
+ it "should preserve IDs of quotes after the removed one" do
110
+ with_quote_log {
111
+ add "One"
112
+ add "Two"
113
+ add "Three"
114
+ del 2
115
+ }
116
+ quotes[3 - 1].should == "Three"
117
+ end
118
+
119
+ it "should display an explanation when !rmquote is given an invalid ID" do
120
+ when_saying "!rmquote 1"
121
+ bot_should_reply "No quote #1."
122
+ end
123
+
124
+ it "should save quotes between runs" do
125
+ with_quote_log {
126
+ add "One"
127
+ add "Two"
128
+ }
129
+ init_plugin # Should re-read the .yml file
130
+ quotes[2 - 1].should == "Two"
131
+ end
132
+
133
+ it "should handle angle brackets appropriately" do
134
+ # One convention for attribution is to place the speaker in brackets.
135
+ # And this is how Campfire+Tinder+CampfireBot send us the message.
136
+ when_saying "!addquote \\u0026lt;Someone\\u0026gt; Hello"
137
+ bot_should_reply "Added quote #1."
138
+ quotes[1 - 1].should == "<Someone> Hello"
139
+ end
140
+
141
+
142
+ before :each do
143
+ @bot = CampfireBot::Bot.instance
144
+ @bot.stub!(:config).and_return('nickname' => 'Bot',
145
+ 'our_quotes_recall_command' => 'quote'
146
+ #,'our_quotes_debug_enabled' => true
147
+ )
148
+ init_plugin
149
+ end
150
+ after :each do
151
+ if File.exist? @quote.data_file
152
+ File.unlink(@quote.data_file)
153
+ end
154
+ end
155
+ def init_plugin
156
+ @quote = OurQuotes.new
157
+ CampfireBot::Plugin.registered_plugins['OurQuotes'] = @quote
158
+ end
159
+
160
+ def when_saying(msg)
161
+ @message = CampfireBot::Message.new(:room => Tinder::Room.new(42, "Room1"),
162
+ :message => msg,
163
+ :person => 'Josh')
164
+ end
165
+ def bot_should_reply(msg)
166
+ @message.should_receive(:speak).with(msg)
167
+ @bot.send(:handle_message, @message)
168
+ end
169
+
170
+ # Group log setup calls into a block
171
+ def with_quote_log
172
+ yield
173
+ end
174
+ # Add a quote to the log
175
+ def add(quote)
176
+ @quote.append_add("Someoneelse", "Room1", quote)
177
+ end
178
+ # Remove a quote from the log by id
179
+ def del(quote_id)
180
+ @quote.append_del("Someoneelse", "Room1", quote_id)
181
+ end
182
+ def quotes
183
+ @quote.quotes
184
+ end
185
+
186
+ end