hipbot 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +6 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +7 -10
- data/README.md +129 -21
- data/bin/hipbot +8 -1
- data/hipbot.gemspec +2 -1
- data/lib/hipbot.rb +8 -7
- data/lib/hipbot/adapters/hipchat/connection.rb +123 -0
- data/lib/hipbot/adapters/hipchat/hipchat.rb +20 -0
- data/lib/hipbot/adapters/{telnet.rb → telnet/connection.rb} +0 -10
- data/lib/hipbot/adapters/telnet/telnet.rb +16 -0
- data/lib/hipbot/bot.rb +10 -9
- data/lib/hipbot/configuration.rb +3 -0
- data/lib/hipbot/http_response.rb +15 -0
- data/lib/hipbot/message.rb +9 -1
- data/lib/hipbot/{encoding.rb → patches/encoding.rb} +0 -0
- data/lib/hipbot/patches/mucclient.rb +147 -0
- data/lib/hipbot/reaction.rb +14 -6
- data/lib/hipbot/response.rb +10 -18
- data/lib/hipbot/room.rb +2 -5
- data/lib/hipbot/version.rb +1 -1
- data/spec/integration/hipbot_spec.rb +33 -4
- data/spec/unit/hipbot_spec.rb +75 -3
- metadata +29 -12
- data/bot.rb +0 -92
- data/lib/hipbot/adapters/hipchat.rb +0 -86
- data/lib/hipbot/mucclient.rb +0 -60
- data/test_server.rb +0 -23
data/spec/unit/hipbot_spec.rb
CHANGED
@@ -44,6 +44,29 @@ describe Hipbot::Bot do
|
|
44
44
|
subject.tell(sender, room, '@robot hello there')
|
45
45
|
end
|
46
46
|
|
47
|
+
context "multiple regexps" do
|
48
|
+
before do
|
49
|
+
subject.on /hello (.*)/, /good morning (.*)/, /guten tag (.*)/ do |name|
|
50
|
+
reply("hello #{name}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should understand simple english" do |msg|
|
55
|
+
subject.expects(:reply).with(room, 'hello tom')
|
56
|
+
subject.tell(sender, room, '@robot hello tom')
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should understand english" do |msg|
|
60
|
+
subject.expects(:reply).with(room, 'hello tom')
|
61
|
+
subject.tell(sender, room, '@robot good morning tom')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should understand german" do |msg|
|
65
|
+
subject.expects(:reply).with(room, 'hello tom')
|
66
|
+
subject.tell(sender, room, '@robot guten tag tom')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
47
70
|
context "global messages" do
|
48
71
|
it "should reply if callback is global" do
|
49
72
|
subject.on /^you are (.*)$/, global: true do |adj|
|
@@ -93,10 +116,43 @@ describe Hipbot::Bot do
|
|
93
116
|
end
|
94
117
|
end
|
95
118
|
|
96
|
-
context "
|
119
|
+
context "messages in particular room" do
|
120
|
+
let(:room) { stub(:name => 'room') }
|
121
|
+
let(:other_room) { stub(:name => 'other_room') }
|
122
|
+
it "should reply" do
|
123
|
+
subject.on /wazzup\?/, room: 'room' do
|
124
|
+
reply('Wazzup, Tom?')
|
125
|
+
end
|
126
|
+
subject.expects(:reply).with(room, 'Wazzup, Tom?')
|
127
|
+
subject.tell(sender, room, '@robot wazzup?')
|
128
|
+
end
|
129
|
+
it "should reply if room acceptable" do
|
130
|
+
subject.on /wazzup\?/, room: ['other_room', 'room'] do
|
131
|
+
reply('wazzup, tom?')
|
132
|
+
end
|
133
|
+
subject.expects(:reply).with(room, 'wazzup, tom?')
|
134
|
+
subject.tell(sender, room, '@robot wazzup?')
|
135
|
+
end
|
136
|
+
it "should not reply if room unacceptable" do
|
137
|
+
subject.on /wazzup\?/, room: 'room' do
|
138
|
+
reply('wazzup, tom?')
|
139
|
+
end
|
140
|
+
subject.expects(:reply).with(other_room, "I don't understand \"wazzup?\"")
|
141
|
+
subject.tell(sender, other_room, '@robot wazzup?')
|
142
|
+
end
|
143
|
+
it "should not reply if room does not match" do
|
144
|
+
subject.on /wazzup\?/, room: ['other_room'] do
|
145
|
+
reply('wazzup, tom?')
|
146
|
+
end
|
147
|
+
subject.expects(:reply).with(room, "I don't understand \"wazzup?\"")
|
148
|
+
subject.tell(sender, room, '@robot wazzup?')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "response helper" do
|
97
153
|
it "message" do
|
98
154
|
subject.on /.*/ do
|
99
|
-
reply("you said: #{message}")
|
155
|
+
reply("you said: #{message.body}")
|
100
156
|
end
|
101
157
|
subject.expects(:reply).with(room, "you said: hello")
|
102
158
|
subject.tell(stub, room, "@robot hello")
|
@@ -112,11 +168,27 @@ describe Hipbot::Bot do
|
|
112
168
|
|
113
169
|
it "recipients" do
|
114
170
|
subject.on /.*/ do
|
115
|
-
reply("recipients: #{recipients.join(', ')}")
|
171
|
+
reply("recipients: #{message.recipients.join(', ')}")
|
116
172
|
end
|
117
173
|
subject.expects(:reply).with(room, "recipients: robot, dave")
|
118
174
|
subject.tell('tom', room, "@robot tell @dave hello from me")
|
119
175
|
end
|
176
|
+
|
177
|
+
it "sender name" do
|
178
|
+
subject.on /.*/ do
|
179
|
+
reply(message.sender_name)
|
180
|
+
end
|
181
|
+
subject.expects(:reply).with(room, 'Tom')
|
182
|
+
subject.tell('Tom Smith', room, '@robot What\'s my name?')
|
183
|
+
end
|
184
|
+
|
185
|
+
it "mentions" do
|
186
|
+
subject.on /.*/ do
|
187
|
+
reply(message.mentions.join(' '))
|
188
|
+
end
|
189
|
+
subject.expects(:reply).with(room, 'dave rachel')
|
190
|
+
subject.tell('Tom Smith', room, '@robot do you know @dave? @dave is @rachel father')
|
191
|
+
end
|
120
192
|
end
|
121
193
|
end
|
122
194
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hipbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: daemons
|
@@ -108,21 +108,37 @@ dependencies:
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0.5'
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
111
|
+
name: rspec
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
113
113
|
none: false
|
114
114
|
requirements:
|
115
115
|
- - ~>
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
118
|
-
type: :
|
117
|
+
version: 2.11.0
|
118
|
+
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
none: false
|
122
122
|
requirements:
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
125
|
+
version: 2.11.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: mocha
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.11.4
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.11.4
|
126
142
|
description: Hipbot is a bot for HipChat, written in ruby & eventmachine.
|
127
143
|
email:
|
128
144
|
- pewniak747@gmail.com
|
@@ -139,16 +155,18 @@ files:
|
|
139
155
|
- README.md
|
140
156
|
- Rakefile
|
141
157
|
- bin/hipbot
|
142
|
-
- bot.rb
|
143
158
|
- hipbot.gemspec
|
144
159
|
- lib/hipbot.rb
|
145
|
-
- lib/hipbot/adapters/hipchat.rb
|
146
|
-
- lib/hipbot/adapters/
|
160
|
+
- lib/hipbot/adapters/hipchat/connection.rb
|
161
|
+
- lib/hipbot/adapters/hipchat/hipchat.rb
|
162
|
+
- lib/hipbot/adapters/telnet/connection.rb
|
163
|
+
- lib/hipbot/adapters/telnet/telnet.rb
|
147
164
|
- lib/hipbot/bot.rb
|
148
165
|
- lib/hipbot/configuration.rb
|
149
|
-
- lib/hipbot/
|
166
|
+
- lib/hipbot/http_response.rb
|
150
167
|
- lib/hipbot/message.rb
|
151
|
-
- lib/hipbot/
|
168
|
+
- lib/hipbot/patches/encoding.rb
|
169
|
+
- lib/hipbot/patches/mucclient.rb
|
152
170
|
- lib/hipbot/reaction.rb
|
153
171
|
- lib/hipbot/response.rb
|
154
172
|
- lib/hipbot/room.rb
|
@@ -157,7 +175,6 @@ files:
|
|
157
175
|
- spec/spec_helper.rb
|
158
176
|
- spec/unit/hipbot_spec.rb
|
159
177
|
- spec/unit/message_spec.rb
|
160
|
-
- test_server.rb
|
161
178
|
homepage: http://github.com/pewniak747/hipbot
|
162
179
|
licenses: []
|
163
180
|
post_install_message:
|
data/bot.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'hipbot'
|
2
|
-
|
3
|
-
class MyBot < Hipbot::Bot
|
4
|
-
configure do |c|
|
5
|
-
c.jid = ENV['HIPBOT_JID']
|
6
|
-
c.password = ENV['HIPBOT_PASSWORD']
|
7
|
-
c.name = ENV['HIPBOT_NAME']
|
8
|
-
end
|
9
|
-
|
10
|
-
# Works for message and response
|
11
|
-
# TODO: Reload existing objects? / Full bot restart
|
12
|
-
on /^reload (.*)/, global: true do |clazz|
|
13
|
-
const = clazz.capitalize.to_sym
|
14
|
-
Hipbot.class_eval do
|
15
|
-
remove_const const if const_defined? const
|
16
|
-
end
|
17
|
-
load("./lib/hipbot/" + clazz + ".rb")
|
18
|
-
reply('Reloaded')
|
19
|
-
end
|
20
|
-
|
21
|
-
on /get (.*)/ do |url|
|
22
|
-
get(url) do |http|
|
23
|
-
reply("Server responded with code: #{http.response_header.status}")
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
on /^wiki (.+)/, global: true do |search|
|
28
|
-
search = URI::encode search
|
29
|
-
get("http://en.wikipedia.org/w/api.php?action=query&format=json&titles=#{search}&prop=extracts&exlimit=3&explaintext=1&exsentences=2") do |http|
|
30
|
-
extracts = JSON.parse http.response.force_encoding 'utf-8'
|
31
|
-
extracts['query']['pages'].each do |page|
|
32
|
-
reply(page[1]['extract'])
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
on /^google (.+)/, global: true do |search|
|
38
|
-
search = URI::encode search
|
39
|
-
get("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&safe=off&q=#{search}") do |http|
|
40
|
-
extracts = JSON.parse http.response.force_encoding 'utf-8'
|
41
|
-
extracts['responseData']['results'].each do |page|
|
42
|
-
reply("#{page['url']} - #{page['titleNoFormatting']}")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
on /weather\s(.*)/ do |city|
|
48
|
-
reply("checking weather for #{city}")
|
49
|
-
conditions = ::GoogleWeather.new(city).forecast_conditions.first
|
50
|
-
reply("weather in #{city} - #{conditions.condition}, max #{conditions.high}F")
|
51
|
-
end
|
52
|
-
|
53
|
-
on /^hello.*/ do
|
54
|
-
reply('hello!')
|
55
|
-
end
|
56
|
-
|
57
|
-
on /deploy to (.*) pls/ do |stage|
|
58
|
-
reply("deploying #{room} to #{stage}!")
|
59
|
-
sleep(3)
|
60
|
-
reply("deployed!")
|
61
|
-
end
|
62
|
-
|
63
|
-
on /.*hello everyone.*/, global: true do
|
64
|
-
reply('hello!')
|
65
|
-
end
|
66
|
-
|
67
|
-
on /sleep/, global: true do
|
68
|
-
reply("sleeping...")
|
69
|
-
sleep(10)
|
70
|
-
reply("woke up")
|
71
|
-
end
|
72
|
-
|
73
|
-
on /help|commands/ do
|
74
|
-
commands = []
|
75
|
-
bot.reactions.each do |r|
|
76
|
-
commands << r.regexp
|
77
|
-
end
|
78
|
-
reply(commands.join("\n"))
|
79
|
-
end
|
80
|
-
|
81
|
-
on /^rand (.*)/, global: true do |message|
|
82
|
-
options = message.split(',').map { |s| s.strip }
|
83
|
-
rsp = options[rand(options.length)]
|
84
|
-
reply("And the winner is... #{rsp}") if rsp
|
85
|
-
end
|
86
|
-
|
87
|
-
on /^debug/, global: true do
|
88
|
-
reply "Debug " + (Jabber::debug = !Jabber::debug ? 'on' : 'off')
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
MyBot.start!
|
@@ -1,86 +0,0 @@
|
|
1
|
-
module Hipbot
|
2
|
-
module Adapters
|
3
|
-
module Hipchat
|
4
|
-
delegate :reply, to: :connection
|
5
|
-
|
6
|
-
class Connection
|
7
|
-
|
8
|
-
def initialize bot
|
9
|
-
initialize_bot(bot)
|
10
|
-
initialize_jabber
|
11
|
-
initialize_rooms
|
12
|
-
join_rooms
|
13
|
-
end
|
14
|
-
|
15
|
-
def reply room, message
|
16
|
-
for_room room do |room|
|
17
|
-
puts("Replied to #{room.name} - #{message}")
|
18
|
-
send_message(room, message)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def initialize_rooms
|
25
|
-
@rooms ||= []
|
26
|
-
@muc_browser = Jabber::MUC::MUCBrowser.new(@jabber)
|
27
|
-
@rooms = @muc_browser.muc_rooms('conf.hipchat.com').map { |jid, name|
|
28
|
-
::Hipbot::Room.new(jid, name)
|
29
|
-
}
|
30
|
-
end
|
31
|
-
|
32
|
-
def initialize_bot bot
|
33
|
-
@bot = bot
|
34
|
-
@bot.connection = self
|
35
|
-
end
|
36
|
-
|
37
|
-
def initialize_jabber
|
38
|
-
@jabber = ::Jabber::Client.new(@bot.jid)
|
39
|
-
@jabber.connect
|
40
|
-
@jabber.auth(@bot.password)
|
41
|
-
end
|
42
|
-
|
43
|
-
def join_rooms
|
44
|
-
rooms.each do |room|
|
45
|
-
puts "joining #{room.name}"
|
46
|
-
room.connection = ::Jabber::MUC::SimpleMUCClient.new(@jabber)
|
47
|
-
room.connection.on_message do |time, sender, message|
|
48
|
-
puts "#{Time.now} <#{sender}> #{message}"
|
49
|
-
begin
|
50
|
-
@bot.tell(sender, room.name, message)
|
51
|
-
rescue => e
|
52
|
-
puts e.inspect
|
53
|
-
end
|
54
|
-
end
|
55
|
-
room.connection.join("#{room.jid}/#{@bot.name}", nil, :history => false)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def for_room room_name
|
60
|
-
room = rooms.find { |r| r.name == room_name }
|
61
|
-
if room.present?
|
62
|
-
yield(room) if block_given?
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def send_message room, message
|
67
|
-
room.connection.say(message)
|
68
|
-
end
|
69
|
-
|
70
|
-
def rooms
|
71
|
-
@rooms || []
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def start!
|
76
|
-
::EM::run do
|
77
|
-
::EM.error_handler do |e|
|
78
|
-
puts e.inspect
|
79
|
-
end
|
80
|
-
Connection.new(self)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
data/lib/hipbot/mucclient.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
module Jabber
|
2
|
-
module MUC
|
3
|
-
class MUCClient
|
4
|
-
def join(jid, password=nil, opts={})
|
5
|
-
if active?
|
6
|
-
raise "MUCClient already active"
|
7
|
-
end
|
8
|
-
|
9
|
-
@jid = (jid.kind_of?(JID) ? jid : JID.new(jid))
|
10
|
-
activate
|
11
|
-
|
12
|
-
# Joining
|
13
|
-
pres = Presence.new
|
14
|
-
pres.to = @jid
|
15
|
-
pres.from = @my_jid
|
16
|
-
xmuc = XMUC.new
|
17
|
-
xmuc.password = password
|
18
|
-
|
19
|
-
if !opts[:history]
|
20
|
-
history = REXML::Element.new( 'history').tap {|h| h.add_attribute('maxstanzas','0') }
|
21
|
-
xmuc.add_element history
|
22
|
-
end
|
23
|
-
|
24
|
-
pres.add(xmuc)
|
25
|
-
|
26
|
-
# We don't use Stream#send_with_id here as it's unknown
|
27
|
-
# if the MUC component *always* uses our stanza id.
|
28
|
-
error = nil
|
29
|
-
@stream.send(pres) { |r|
|
30
|
-
if from_room?(r.from) and r.kind_of?(Presence) and r.type == :error
|
31
|
-
# Error from room
|
32
|
-
error = r.error
|
33
|
-
true
|
34
|
-
# type='unavailable' may occur when the MUC kills our previous instance,
|
35
|
-
# but all join-failures should be type='error'
|
36
|
-
elsif r.from == jid and r.kind_of?(Presence) and r.type != :unavailable
|
37
|
-
# Our own presence reflected back - success
|
38
|
-
if r.x(XMUCUser) and (i = r.x(XMUCUser).items.first)
|
39
|
-
@affiliation = i.affiliation # we're interested in if it's :owner
|
40
|
-
@role = i.role # :moderator ?
|
41
|
-
end
|
42
|
-
|
43
|
-
handle_presence(r, false)
|
44
|
-
true
|
45
|
-
else
|
46
|
-
# Everything else
|
47
|
-
false
|
48
|
-
end
|
49
|
-
}
|
50
|
-
|
51
|
-
if error
|
52
|
-
deactivate
|
53
|
-
raise ServerError.new(error)
|
54
|
-
end
|
55
|
-
|
56
|
-
self
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/test_server.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
|
3
|
-
$connections = []
|
4
|
-
|
5
|
-
class ChatServer < EM::Connection
|
6
|
-
def post_init
|
7
|
-
$connections << self
|
8
|
-
end
|
9
|
-
|
10
|
-
def receive_data data
|
11
|
-
messages = data.split("\n").map{ |m| "#{m}\n" }.each do |msg|
|
12
|
-
sender, room, message = *msg.strip.split(':')
|
13
|
-
$connections.reject{|c| c==self}.each do |connection|
|
14
|
-
connection.send_data msg
|
15
|
-
end
|
16
|
-
puts "#{sender}@#{room} > #{message}"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
EM::run do
|
22
|
-
EM::start_server('0.0.0.0', 3001, ChatServer)
|
23
|
-
end
|