hipbot 1.0.0.rc2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +6 -0
  4. data/Gemfile +1 -2
  5. data/README.md +482 -88
  6. data/Rakefile +1 -1
  7. data/bin/hipbot +4 -4
  8. data/hipbot.gemspec +9 -9
  9. data/lib/hipbot.rb +28 -11
  10. data/lib/hipbot/adapter.rb +80 -0
  11. data/lib/hipbot/adapters/hipchat.rb +53 -0
  12. data/lib/hipbot/adapters/hipchat/initializer.rb +83 -0
  13. data/lib/hipbot/adapters/shell.rb +37 -0
  14. data/lib/hipbot/adapters/telnet.rb +41 -0
  15. data/lib/hipbot/bot.rb +15 -52
  16. data/lib/hipbot/cache.rb +23 -0
  17. data/lib/hipbot/callbacks/base.rb +15 -0
  18. data/lib/hipbot/callbacks/invite.rb +11 -0
  19. data/lib/hipbot/callbacks/lobby_presence.rb +13 -0
  20. data/lib/hipbot/callbacks/message.rb +11 -0
  21. data/lib/hipbot/callbacks/presence.rb +17 -0
  22. data/lib/hipbot/callbacks/private_message.rb +12 -0
  23. data/lib/hipbot/callbacks/room_message.rb +21 -0
  24. data/lib/hipbot/callbacks/room_presence.rb +28 -0
  25. data/lib/hipbot/configurable.rb +22 -0
  26. data/lib/hipbot/configuration.rb +9 -3
  27. data/lib/hipbot/helpers.rb +4 -40
  28. data/lib/hipbot/http.rb +65 -0
  29. data/lib/hipbot/match.rb +21 -9
  30. data/lib/hipbot/matchable.rb +38 -0
  31. data/lib/hipbot/message.rb +24 -9
  32. data/lib/hipbot/plugin.rb +3 -3
  33. data/lib/hipbot/reactable.rb +14 -21
  34. data/lib/hipbot/reaction.rb +27 -15
  35. data/lib/hipbot/reaction_factory.rb +38 -0
  36. data/lib/hipbot/response.rb +18 -10
  37. data/lib/hipbot/room.rb +34 -2
  38. data/lib/hipbot/storages/base.rb +78 -0
  39. data/lib/hipbot/storages/hash.rb +89 -0
  40. data/lib/hipbot/storages/mongoid.rb +18 -0
  41. data/lib/hipbot/user.rb +8 -2
  42. data/lib/hipbot/version.rb +1 -1
  43. data/spec/integration/my_hipbot.rb +24 -4
  44. data/spec/integration/{hipbot_spec.rb → my_hipbot_spec.rb} +41 -23
  45. data/spec/spec_helper.rb +14 -2
  46. data/spec/unit/adapters/hipchat_spec.rb +5 -0
  47. data/spec/unit/{hipbot_spec.rb → bot_spec.rb} +13 -12
  48. data/spec/unit/match_spec.rb +148 -0
  49. data/spec/unit/message_spec.rb +14 -7
  50. data/spec/unit/reaction_factory_spec.rb +54 -0
  51. data/spec/unit/reaction_spec.rb +99 -0
  52. data/spec/unit/storages/hash_spec.rb +75 -0
  53. data/spec/unit/user_spec.rb +0 -2
  54. metadata +64 -54
  55. data/Gemfile.lock +0 -90
  56. data/examples/cleverbot.rb +0 -23
  57. data/examples/google_images.rb +0 -35
  58. data/lib/hipbot/adapters/hipchat/connection.rb +0 -166
  59. data/lib/hipbot/adapters/hipchat/hipchat.rb +0 -13
  60. data/lib/hipbot/adapters/telnet/connection.rb +0 -17
  61. data/lib/hipbot/adapters/telnet/telnet.rb +0 -14
  62. data/lib/hipbot/collection.rb +0 -72
  63. data/lib/hipbot/patches/hipchat_client.rb +0 -230
@@ -0,0 +1,18 @@
1
+ module Hipbot
2
+ module Storages
3
+ module Mongoid
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include ::Mongoid::Document
8
+
9
+ field :_id, type: String
10
+ field :name, type: String
11
+
12
+ alias_method :to_s, :name
13
+
14
+ validate :name, presence: true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,7 +1,5 @@
1
1
  module Hipbot
2
2
  class User
3
- include Reactable
4
-
5
3
  def send_message message
6
4
  Hipbot.send_to_user self, message
7
5
  end
@@ -13,5 +11,13 @@ module Hipbot
13
11
  def first_name
14
12
  name.split.first
15
13
  end
14
+
15
+ def myself?
16
+ self == Hipbot.user
17
+ end
18
+
19
+ def guest?
20
+ attributes[:role] == 'visitor'
21
+ end
16
22
  end
17
23
  end
@@ -1,3 +1,3 @@
1
1
  module Hipbot
2
- VERSION = "1.0.0.rc2"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -15,6 +15,26 @@ class AwesomePlugin
15
15
  on /respond awesome/ do
16
16
  reply('awesome responded')
17
17
  end
18
+
19
+ def method_reaction param = 'empty'
20
+ reply("parameter: #{param}")
21
+ end
22
+
23
+ on /^method reaction$/, :method_reaction
24
+ on /^method reaction (.*)$/, :method_reaction
25
+ on /^no block reaction$/
26
+
27
+ def scope_method_reaction
28
+ reply('scope method reaction')
29
+ end
30
+
31
+ scope :scope_method_reaction do
32
+ on /^scope method reaction$/
33
+ end
34
+
35
+ scope /^scope regexp$/ do
36
+ on :method_reaction
37
+ end
18
38
  end
19
39
 
20
40
  class CoolPlugin
@@ -24,6 +44,10 @@ class CoolPlugin
24
44
  on /respond cool/ do
25
45
  reply('cool responded')
26
46
  end
47
+
48
+ default do
49
+ reply("I didn't understand you")
50
+ end
27
51
  end
28
52
 
29
53
  class MyHipbot < Hipbot::Bot
@@ -39,10 +63,6 @@ class MyHipbot < Hipbot::Bot
39
63
  reply('What do you mean, Other Guy?')
40
64
  end
41
65
 
42
- default do
43
- reply("I didn't understand you")
44
- end
45
-
46
66
  desc 'greets the user'
47
67
  on /^hello hipbot!$/ do
48
68
  reply('hello!')
@@ -10,13 +10,9 @@ describe MyHipbot do
10
10
  let(:other_room) { Hipbot::Room.create(id: '2', name: 'Hyde Park', topic: 'nice weather today') }
11
11
  let(:other_sender) { Hipbot::User.create(id: '2', name: 'Other Guy') }
12
12
 
13
- before do
14
- Hipbot.bot.configuration.user = Hipbot::User.create(name: 'robbot')
15
- end
16
-
17
13
  describe 'configuration' do
18
14
  it 'should set robot name' do
19
- subject.name.should == 'robbot'
15
+ subject.name.should == 'robot'
20
16
  end
21
17
 
22
18
  it 'should set hipchat token' do
@@ -27,12 +23,12 @@ describe MyHipbot do
27
23
  describe 'replying' do
28
24
  it 'should reply to hello' do
29
25
  subject.expects(:send_to_room).with(room, 'hello!')
30
- subject.react(sender, room, '@robbot hello hipbot!')
26
+ subject.react(sender, room, '@robot hello hipbot!')
31
27
  end
32
28
 
33
29
  it 'should reply with argument' do
34
30
  subject.expects(:send_to_room).with(room, "I know I'm cool")
35
- subject.react(sender, room, '@robbot you\'re cool, robot')
31
+ subject.react(sender, room, '@robot you\'re cool, robot')
36
32
  end
37
33
 
38
34
  it 'should reply to global message' do
@@ -42,38 +38,38 @@ describe MyHipbot do
42
38
 
43
39
  it 'should respond with default reply' do
44
40
  subject.expects(:send_to_room).with(room, "I didn't understand you")
45
- subject.react(sender, room, '@robbot blahlblah')
41
+ subject.react(sender, room, '@robot blahlblah')
46
42
  end
47
43
  end
48
44
 
49
45
  describe '"from" option' do
50
46
  it 'reacts to sender from required team' do
51
47
  subject.expects(:send_to_room).with(room, 'restarting')
52
- subject.react(sender, room, '@robbot restart')
48
+ subject.react(sender, room, '@robot restart')
53
49
  end
54
50
 
55
51
  it 'ignores sender when not in team' do
56
52
  subject.expects(:send_to_room).with(room, 'What do you mean, Other Guy?')
57
- subject.react(other_sender, room, '@robbot restart')
53
+ subject.react(other_sender, room, '@robot restart')
58
54
  end
59
55
  end
60
56
 
61
57
  describe '"room" option' do
62
58
  it 'reacts in required room' do
63
59
  subject.expects(:send_to_room).with(room, 'deploying')
64
- subject.react(sender, room, '@robbot deploy')
60
+ subject.react(sender, room, '@robot deploy')
65
61
  end
66
62
 
67
63
  it 'ignores other rooms' do
68
64
  subject.expects(:send_to_room).with(other_room, "I didn't understand you")
69
- subject.react(sender, other_room, '@robbot deploy')
65
+ subject.react(sender, other_room, '@robot deploy')
70
66
  end
71
67
  end
72
68
 
73
69
  describe 'room=true' do
74
70
  it 'reacts in any room' do
75
71
  subject.expects(:send_to_room).with(room, 'doing room thing')
76
- subject.react(sender, room, '@robbot room thing')
72
+ subject.react(sender, room, '@robot room thing')
77
73
  end
78
74
 
79
75
  it 'ignores room commands if not in room' do
@@ -85,7 +81,7 @@ describe MyHipbot do
85
81
  describe 'room=false' do
86
82
  it 'ignores private command in room' do
87
83
  subject.expects(:send_to_room).with(room, "I didn't understand you")
88
- subject.react(sender, room, '@robbot private thing')
84
+ subject.react(sender, room, '@robot private thing')
89
85
  end
90
86
 
91
87
  it 'allows private command if not in room' do
@@ -97,51 +93,73 @@ describe MyHipbot do
97
93
  describe 'scope' do
98
94
  it 'sets its attributes to every reaction inside' do
99
95
  subject.expects(:send_to_room).with(room, 'doing John Doe thing')
100
- subject.react(sender, room, '@robbot John Doe thing')
96
+ subject.react(sender, room, '@robot John Doe thing')
101
97
  end
102
98
 
103
99
  it 'does not match other senders' do
104
100
  subject.expects(:send_to_room).with(room, 'What do you mean, Other Guy?')
105
- subject.react(other_sender, room, '@robbot John Doe thing')
101
+ subject.react(other_sender, room, '@robot John Doe thing')
106
102
  end
107
103
 
108
104
  it 'merges params if embedded' do
109
105
  subject.expects(:send_to_room).with(room, 'doing John Doe project thing')
110
- subject.react(sender, room, '@robbot John Doe project thing')
106
+ subject.react(sender, room, '@robot John Doe project thing')
111
107
  end
112
108
 
113
109
  it 'ignores message from same sander in other room' do
114
110
  subject.expects(:send_to_room).with(other_room, "I didn't understand you")
115
- subject.react(sender, other_room, '@robbot John Doe project thing')
111
+ subject.react(sender, other_room, '@robot John Doe project thing')
116
112
  end
117
113
 
118
114
  it 'ignores message from other sender in same room' do
119
115
  subject.expects(:send_to_room).with(room, 'What do you mean, Other Guy?')
120
- subject.react(other_sender, room, '@robbot John Doe project thing')
116
+ subject.react(other_sender, room, '@robot John Doe project thing')
121
117
  end
122
118
  end
123
119
 
124
120
  describe 'custom helpers' do
125
121
  it 'should have access to room variable' do
126
122
  subject.expects(:send_to_room).with(room, 'Project: Project 1')
127
- subject.react(sender, room, '@robbot tell me the project name')
123
+ subject.react(sender, room, '@robot tell me the project name')
128
124
  end
129
125
 
130
126
  it 'should have access to message variable' do
131
127
  subject.expects(:send_to_room).with(room, 'you are John')
132
- subject.react(sender, room, '@robbot tell me my name')
128
+ subject.react(sender, room, '@robot tell me my name')
133
129
  end
134
130
  end
135
131
 
136
132
  describe 'plugins' do
137
133
  it 'should reply to reaction defined in plugin' do
138
134
  subject.expects(:send_to_room).with(room, 'awesome responded')
139
- subject.react(sender, room, '@robbot respond awesome')
135
+ subject.react(sender, room, '@robot respond awesome')
140
136
  end
141
137
 
142
138
  it 'should reply to reaction defined in second plugin' do
143
139
  subject.expects(:send_to_room).with(room, 'cool responded')
144
- subject.react(sender, room, '@robbot respond cool')
140
+ subject.react(sender, room, '@robot respond cool')
141
+ end
142
+ end
143
+
144
+ describe 'method reaction' do
145
+ it 'should reply to a method reaction defined in plugin' do
146
+ subject.expects(:send_to_room).with(room, 'parameter: empty')
147
+ subject.react(sender, room, '@robot method reaction')
148
+ end
149
+
150
+ it 'should reply to a method reaction defined in plugin with parameters' do
151
+ subject.expects(:send_to_room).with(room, 'parameter: method param')
152
+ subject.react(sender, room, '@robot method reaction method param')
153
+ end
154
+
155
+ it 'should reply to a scope method reaction defined in plugin' do
156
+ subject.expects(:send_to_room).with(room, 'scope method reaction')
157
+ subject.react(sender, room, '@robot scope method reaction')
158
+ end
159
+
160
+ it 'should reply to a scope regexp with method reaction defined in plugin', focus: true do
161
+ subject.expects(:send_to_room).with(room, 'parameter: empty')
162
+ subject.react(sender, room, '@robot scope regexp')
145
163
  end
146
164
  end
147
165
  end
@@ -1,8 +1,20 @@
1
1
  require_relative '../lib/hipbot'
2
2
 
3
- require 'coveralls'
4
- Coveralls.wear!
3
+ # require 'coveralls'
4
+ # Coveralls.wear!
5
5
 
6
6
  RSpec.configure do |config|
7
7
  config.mock_with :mocha
8
+
9
+ config.before(:all) do
10
+ Hipbot::User.send(:include, Hipbot::Storages::Hash)
11
+ Hipbot::Room.send(:include, Hipbot::Storages::Hash)
12
+ Hipbot.stubs(logger: NullLogger.instance)
13
+ end
14
+ end
15
+
16
+ class NullLogger
17
+ def self.instance
18
+ Logger.new('/dev/null')
19
+ end
8
20
  end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hipbot::Adapters::Hipchat do
4
+
5
+ end
@@ -5,13 +5,15 @@ describe "a class that inherits", Hipbot::Bot do
5
5
 
6
6
  before(:each) do
7
7
  described_class.instance.plugins.clear
8
+ described_class.instance.configuration.logger = NullLogger.instance
8
9
  described_class.instance.setup
9
10
  end
10
11
  subject { described_class.instance }
11
12
 
13
+ let(:room) { Hipbot::Room.new(name: 'Test Room') }
14
+
12
15
  context "#on" do
13
- let(:sender) { stub_everything(name: 'Tom Smith', reactions: []) }
14
- let(:room) { stub_everything }
16
+ let(:sender) { Hipbot::User.new(name: 'Tom Smith') }
15
17
 
16
18
  it "should reply to no arguments" do
17
19
  described_class.on /^hello there$/ do
@@ -94,7 +96,7 @@ describe "a class that inherits", Hipbot::Bot do
94
96
  end
95
97
 
96
98
  context "messages from particular sender" do
97
- let(:other_user) { stub(name: "John", reactions: []) }
99
+ let(:other_user) { Hipbot::User.new(name: "John") }
98
100
 
99
101
  it "should reply" do
100
102
  described_class.on /wazzup\?/, from: sender.name do
@@ -105,7 +107,7 @@ describe "a class that inherits", Hipbot::Bot do
105
107
  end
106
108
 
107
109
  it "should reply if sender acceptable" do
108
- described_class.on /wazzup\?/, from: [stub, sender.name] do
110
+ described_class.on /wazzup\?/, from: ['someone', sender.name] do
109
111
  reply('wazzup, tom?')
110
112
  end
111
113
  subject.expects(:send_to_room).with(room, 'wazzup, tom?')
@@ -130,11 +132,10 @@ describe "a class that inherits", Hipbot::Bot do
130
132
  end
131
133
 
132
134
  context "messages in particular room" do
133
- let(:room) { stub(:name => 'room') }
134
- let(:other_room) { stub(:name => 'other_room') }
135
+ let(:other_room) { Hipbot::Room.new(name: 'Test Room 2') }
135
136
 
136
137
  it "should reply" do
137
- described_class.on /wazzup\?/, room: 'room' do
138
+ described_class.on /wazzup\?/, room: 'Test Room' do
138
139
  reply('Wazzup, Tom?')
139
140
  end
140
141
  subject.expects(:send_to_room).with(room, 'Wazzup, Tom?')
@@ -142,7 +143,7 @@ describe "a class that inherits", Hipbot::Bot do
142
143
  end
143
144
 
144
145
  it "should reply if room acceptable" do
145
- described_class.on /wazzup\?/, room: ['other_room', 'room'] do
146
+ described_class.on /wazzup\?/, room: ['Test Room 2', 'Test Room'] do
146
147
  reply('wazzup, tom?')
147
148
  end
148
149
  subject.expects(:send_to_room).with(room, 'wazzup, tom?')
@@ -150,7 +151,7 @@ describe "a class that inherits", Hipbot::Bot do
150
151
  end
151
152
 
152
153
  it "should not reply if room unacceptable" do
153
- described_class.on /wazzup\?/, room: 'room' do
154
+ described_class.on /wazzup\?/, room: 'Test Room' do
154
155
  reply('wazzup, tom?')
155
156
  end
156
157
  subject.expects(:send_to_room).never
@@ -158,7 +159,7 @@ describe "a class that inherits", Hipbot::Bot do
158
159
  end
159
160
 
160
161
  it "should not reply if room does not match" do
161
- described_class.on /wazzup\?/, room: ['other_room'] do
162
+ described_class.on /wazzup\?/, room: ['Test Room 2'] do
162
163
  reply('wazzup, tom?')
163
164
  end
164
165
  subject.expects(:send_to_room).never
@@ -167,7 +168,7 @@ describe "a class that inherits", Hipbot::Bot do
167
168
  end
168
169
 
169
170
  context "response helper" do
170
- let(:user){ stub(name: 'Tom Smith', first_name: 'Tom', reactions: []) }
171
+ let(:user){ Hipbot::User.new(name: 'Tom Smith') }
171
172
 
172
173
  it "message" do
173
174
  described_class.on /.*/ do
@@ -259,7 +260,7 @@ describe "a class that inherits", Hipbot::Bot do
259
260
  end
260
261
 
261
262
  describe "configurable options" do
262
- Hipbot::Bot::CONFIGURABLE_OPTIONS.each do |option|
263
+ Hipbot::Configuration::OPTIONS.each do |option|
263
264
  it "should delegate #{option} to configuration" do
264
265
  value = stub
265
266
  subject.configuration.expects(option).returns(value)
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hipbot::Match do
4
+ subject { described_class.new(reaction, message) }
5
+
6
+ let(:message) { stub(for?: true, body: 'test message') }
7
+ let(:reaction) do
8
+ stub(
9
+ global?: false,
10
+ from_anywhere?: true,
11
+ to_anything?: false,
12
+ from_all?: true,
13
+ regexps: [/.*/],
14
+ condition: proc { true }
15
+ )
16
+ end
17
+
18
+ before do
19
+ Hipbot.stubs(:user)
20
+ end
21
+
22
+ describe "#matches?" do
23
+ its(:matches?) { should be_true }
24
+
25
+ describe "specific regexp" do
26
+ describe "matching the message body" do
27
+ before do
28
+ message.stubs(body: 'test message')
29
+ reaction.stubs(regexps: [/\Atest/])
30
+ end
31
+
32
+ its(:matches?) { should be_true }
33
+ end
34
+
35
+ describe "not matching message body" do
36
+ before do
37
+ message.stubs(body: 'test message')
38
+ reaction.stubs(regexps: [/\Arandom/])
39
+ end
40
+
41
+ its(:matches?) { should be_false }
42
+ end
43
+ end
44
+
45
+ describe "multiple regexps" do
46
+ describe "matching message body" do
47
+ before do
48
+ message.stubs(body: 'test message')
49
+ reaction.stubs(regexps: [/\Awat/, /\Atest/])
50
+ end
51
+
52
+ its(:matches?) { should be_true }
53
+ end
54
+
55
+ describe "not matching message body" do
56
+ before do
57
+ message.stubs(body: 'test message')
58
+ reaction.stubs(regexps: [/\Awat/, /\Arandom/])
59
+ end
60
+
61
+ its(:matches?) { should be_false }
62
+ end
63
+ end
64
+
65
+ describe "specific condition" do
66
+ describe "returning true" do
67
+ before do
68
+ reaction.stubs(condition: proc { true })
69
+ end
70
+
71
+ its(:matches?) { should be_true }
72
+ end
73
+
74
+ describe "returning false" do
75
+ before do
76
+ reaction.stubs(condition: proc { false })
77
+ end
78
+
79
+ its(:matches?) { should be_false }
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "#invoke" do
85
+ let(:response) { stub }
86
+
87
+ before do
88
+ Hipbot::Response.stubs(new: response)
89
+ end
90
+
91
+ after do
92
+ subject.invoke
93
+ end
94
+
95
+ describe "a reaction with no regexps" do
96
+ before do
97
+ reaction.stubs(to_anything?: true)
98
+ end
99
+
100
+ it "calls response with message body" do
101
+ response.expects(:invoke).with([message.body])
102
+ end
103
+ end
104
+
105
+ describe "a reaction with regexp with no variables" do
106
+ before do
107
+ reaction.stubs(regexps: [/.*/])
108
+ end
109
+
110
+ it "calls response with message body" do
111
+ response.expects(:invoke).with([])
112
+ end
113
+ end
114
+
115
+ describe "a reaction with regexp with one variable" do
116
+ before do
117
+ message.stubs(body: 'I like trains.')
118
+ reaction.stubs(regexps: [/\Ai like (\w+)/i])
119
+ end
120
+
121
+ it "calls response with variable parsed out of message body" do
122
+ response.expects(:invoke).with(['trains'])
123
+ end
124
+ end
125
+
126
+ describe "a reaction with regexp with multiple variables" do
127
+ before do
128
+ message.stubs(body: 'I like trains and cars.')
129
+ reaction.stubs(regexps: [/\Ai like (\w+) and (\w+)/i])
130
+ end
131
+
132
+ it "calls response with variables parsed out of message body" do
133
+ response.expects(:invoke).with(%w{trains cars})
134
+ end
135
+ end
136
+
137
+ describe "a reaction with multiple regexps with variables" do
138
+ before do
139
+ message.stubs(body: 'I enjoy trains and cars.')
140
+ reaction.stubs(regexps: [/\AI enjoy (\w+) and (\w+)/, /\Ai like (\w+) and (\w+)/i])
141
+ end
142
+
143
+ it "calls response with variable parsed out of message body" do
144
+ response.expects(:invoke).with(%w{trains cars})
145
+ end
146
+ end
147
+ end
148
+ end