hipbot 1.0.0.rc2 → 1.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +6 -0
- data/Gemfile +1 -2
- data/README.md +482 -88
- data/Rakefile +1 -1
- data/bin/hipbot +4 -4
- data/hipbot.gemspec +9 -9
- data/lib/hipbot.rb +28 -11
- data/lib/hipbot/adapter.rb +80 -0
- data/lib/hipbot/adapters/hipchat.rb +53 -0
- data/lib/hipbot/adapters/hipchat/initializer.rb +83 -0
- data/lib/hipbot/adapters/shell.rb +37 -0
- data/lib/hipbot/adapters/telnet.rb +41 -0
- data/lib/hipbot/bot.rb +15 -52
- data/lib/hipbot/cache.rb +23 -0
- data/lib/hipbot/callbacks/base.rb +15 -0
- data/lib/hipbot/callbacks/invite.rb +11 -0
- data/lib/hipbot/callbacks/lobby_presence.rb +13 -0
- data/lib/hipbot/callbacks/message.rb +11 -0
- data/lib/hipbot/callbacks/presence.rb +17 -0
- data/lib/hipbot/callbacks/private_message.rb +12 -0
- data/lib/hipbot/callbacks/room_message.rb +21 -0
- data/lib/hipbot/callbacks/room_presence.rb +28 -0
- data/lib/hipbot/configurable.rb +22 -0
- data/lib/hipbot/configuration.rb +9 -3
- data/lib/hipbot/helpers.rb +4 -40
- data/lib/hipbot/http.rb +65 -0
- data/lib/hipbot/match.rb +21 -9
- data/lib/hipbot/matchable.rb +38 -0
- data/lib/hipbot/message.rb +24 -9
- data/lib/hipbot/plugin.rb +3 -3
- data/lib/hipbot/reactable.rb +14 -21
- data/lib/hipbot/reaction.rb +27 -15
- data/lib/hipbot/reaction_factory.rb +38 -0
- data/lib/hipbot/response.rb +18 -10
- data/lib/hipbot/room.rb +34 -2
- data/lib/hipbot/storages/base.rb +78 -0
- data/lib/hipbot/storages/hash.rb +89 -0
- data/lib/hipbot/storages/mongoid.rb +18 -0
- data/lib/hipbot/user.rb +8 -2
- data/lib/hipbot/version.rb +1 -1
- data/spec/integration/my_hipbot.rb +24 -4
- data/spec/integration/{hipbot_spec.rb → my_hipbot_spec.rb} +41 -23
- data/spec/spec_helper.rb +14 -2
- data/spec/unit/adapters/hipchat_spec.rb +5 -0
- data/spec/unit/{hipbot_spec.rb → bot_spec.rb} +13 -12
- data/spec/unit/match_spec.rb +148 -0
- data/spec/unit/message_spec.rb +14 -7
- data/spec/unit/reaction_factory_spec.rb +54 -0
- data/spec/unit/reaction_spec.rb +99 -0
- data/spec/unit/storages/hash_spec.rb +75 -0
- data/spec/unit/user_spec.rb +0 -2
- metadata +64 -54
- data/Gemfile.lock +0 -90
- data/examples/cleverbot.rb +0 -23
- data/examples/google_images.rb +0 -35
- data/lib/hipbot/adapters/hipchat/connection.rb +0 -166
- data/lib/hipbot/adapters/hipchat/hipchat.rb +0 -13
- data/lib/hipbot/adapters/telnet/connection.rb +0 -17
- data/lib/hipbot/adapters/telnet/telnet.rb +0 -14
- data/lib/hipbot/collection.rb +0 -72
- data/lib/hipbot/patches/hipchat_client.rb +0 -230
data/lib/hipbot/cache.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hipbot
|
2
|
+
module Cache
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
def _cache
|
10
|
+
@_cache ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def attr_cache *attributes, &block
|
15
|
+
attributes.each do |attr_name|
|
16
|
+
define_method(attr_name) do
|
17
|
+
_cache[attr_name] ||= block_given? ? instance_eval(&block) : []
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Hipbot
|
2
|
+
module Callbacks
|
3
|
+
class PrivateMessage < Message
|
4
|
+
def initialize user_id, message_body
|
5
|
+
with_user(id: user_id) do |user|
|
6
|
+
return if ignore_message?(user, message_body)
|
7
|
+
Hipbot.react(user, nil, message_body)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hipbot
|
2
|
+
module Callbacks
|
3
|
+
class RoomMessage < Message
|
4
|
+
def initialize room_id, user_name, message_body, topic
|
5
|
+
with_room(id: room_id) do |room|
|
6
|
+
update_topic(room, topic)
|
7
|
+
with_user(name: user_name) do |user|
|
8
|
+
return if ignore_message?(user, message_body)
|
9
|
+
Hipbot.react(user, room, message_body)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def update_topic room, topic
|
17
|
+
room.update_attribute(:topic, topic) unless topic.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Hipbot
|
2
|
+
module Callbacks
|
3
|
+
class RoomPresence < Presence
|
4
|
+
attr_accessor :room_id, :user_name
|
5
|
+
|
6
|
+
def initialize room_id, user_name, presence
|
7
|
+
self.presence = presence
|
8
|
+
self.user_name = user_name
|
9
|
+
self.room_id = room_id
|
10
|
+
handle_room_presence
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def handle_room_presence
|
16
|
+
with_room(id: room_id) do |room|
|
17
|
+
with_user(name: user_name) do |user|
|
18
|
+
if offline_presence?
|
19
|
+
room.on_leave(user)
|
20
|
+
elsif online_presence? && !room.users.include?(user)
|
21
|
+
room.on_join(user)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Hipbot
|
2
|
+
module Configurable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
attr_accessor :configuration
|
5
|
+
|
6
|
+
delegate *Configuration::OPTIONS, to: :configuration
|
7
|
+
|
8
|
+
included do
|
9
|
+
extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
self.configuration ||= Configuration.new
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def configure &block
|
18
|
+
instance.configuration = Configuration.new.tap(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hipbot/configuration.rb
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
module Hipbot
|
2
2
|
class Configuration
|
3
|
-
|
3
|
+
OPTIONS = [
|
4
|
+
:adapter, :exception_handler, :helpers, :jid, :join, :logger, :password,
|
5
|
+
:plugins, :preloader, :rooms, :status, :storage, :teams, :user
|
6
|
+
]
|
7
|
+
attr_accessor *OPTIONS
|
4
8
|
|
5
9
|
def initialize
|
6
10
|
self.adapter = Adapters::Hipchat
|
7
|
-
self.
|
11
|
+
self.exception_handler = Proc.new{ |e| Hipbot.logger.error(e) }
|
8
12
|
self.helpers = Module.new
|
9
13
|
self.jid = ''
|
14
|
+
self.join = :all
|
10
15
|
self.logger = Logger.new($stdout)
|
11
16
|
self.password = ''
|
12
17
|
self.plugins = Hipbot.plugins
|
13
18
|
self.preloader = Proc.new{}
|
14
19
|
self.rooms = {}
|
15
|
-
self.
|
20
|
+
self.status = ''
|
21
|
+
self.storage = Storages::Hash
|
16
22
|
self.teams = {}
|
17
23
|
end
|
18
24
|
|
data/lib/hipbot/helpers.rb
CHANGED
@@ -1,46 +1,10 @@
|
|
1
1
|
module Hipbot
|
2
2
|
module Helpers
|
3
|
-
[:get, :post, :put, :delete].each do |
|
4
|
-
define_method
|
5
|
-
|
6
|
-
query.merge!({ :head => {'accept-encoding' => 'gzip, compressed'} })
|
7
|
-
conn = ::EM::HttpRequest.new(url, :connect_timeout => 5, :inactivity_timeout => 10)
|
8
|
-
http = conn.send(http_verb, :query => query)
|
9
|
-
http.callback do
|
10
|
-
begin
|
11
|
-
response = HttpResponse.new(http)
|
12
|
-
Hipbot.logger.info("HTTP-RESPONSE: #{response}")
|
13
|
-
block.call(response)
|
14
|
-
rescue => e
|
15
|
-
Hipbot.logger.error(e)
|
16
|
-
instance_exec(e, &Hipbot.error_handler)
|
17
|
-
end
|
18
|
-
end if block.present?
|
19
|
-
|
20
|
-
http.errback do
|
21
|
-
Hipbot.logger.error("HTTP-RESPONSE-ERROR: #{url}")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
module_function http_verb
|
26
|
-
end
|
27
|
-
|
28
|
-
class HttpResponse < Struct.new(:raw_response)
|
29
|
-
def body
|
30
|
-
raw_response.response
|
31
|
-
end
|
32
|
-
|
33
|
-
def code
|
34
|
-
raw_response.response_header.status
|
35
|
-
end
|
36
|
-
|
37
|
-
def headers
|
38
|
-
raw_response.response_header
|
39
|
-
end
|
40
|
-
|
41
|
-
def json
|
42
|
-
@json ||= JSON.parse(body)
|
3
|
+
[:get, :post, :put, :delete].each do |method|
|
4
|
+
define_method method do |url, query = {}, &block|
|
5
|
+
Http::Request.new(url, query, method).(&block)
|
43
6
|
end
|
7
|
+
module_function method
|
44
8
|
end
|
45
9
|
end
|
46
10
|
end
|
data/lib/hipbot/http.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Hipbot
|
3
|
+
module Http
|
4
|
+
class Request < Struct.new(:url, :params, :method)
|
5
|
+
DEFAULT_HEADERS = { 'accept-encoding' => 'gzip, compressed' }.freeze
|
6
|
+
CONNECTION_SETTINGS = { connect_timeout: 5, inactivity_timeout: 10 }.freeze
|
7
|
+
ERROR_CALLBACK = ->(error){ Hipbot.logger.error(error) }
|
8
|
+
|
9
|
+
def initialize *args
|
10
|
+
super
|
11
|
+
self.params ||= {}
|
12
|
+
self.params = params.has_key?(:query) ? params : { query: params }
|
13
|
+
self.params = { head: DEFAULT_HEADERS }.merge(params)
|
14
|
+
Hipbot.logger.info("HTTP-REQUEST: #{url} #{params}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def call &success_block
|
18
|
+
http.errback(&ERROR_CALLBACK)
|
19
|
+
http.callback do
|
20
|
+
success(&success_block)
|
21
|
+
end unless success_block.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def success
|
27
|
+
yield Http::Response.new(http)
|
28
|
+
rescue => e
|
29
|
+
instance_exec(e, &Hipbot.exception_handler)
|
30
|
+
end
|
31
|
+
|
32
|
+
def http options = {}
|
33
|
+
@http ||= connection.send(method, params.merge(options))
|
34
|
+
end
|
35
|
+
|
36
|
+
def connection
|
37
|
+
@connection ||= EM::HttpRequest.new(url, CONNECTION_SETTINGS)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Response < Struct.new(:raw_response)
|
42
|
+
def initialize *args
|
43
|
+
super
|
44
|
+
Hipbot.logger.debug("HTTP-RESPONSE: #{body}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def body
|
48
|
+
raw_response.response
|
49
|
+
end
|
50
|
+
|
51
|
+
def code
|
52
|
+
raw_response.response_header.status
|
53
|
+
end
|
54
|
+
|
55
|
+
def headers
|
56
|
+
raw_response.response_header
|
57
|
+
end
|
58
|
+
|
59
|
+
def json
|
60
|
+
binding.pry
|
61
|
+
@json ||= JSON.parse(body) || {}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/hipbot/match.rb
CHANGED
@@ -1,25 +1,27 @@
|
|
1
1
|
module Hipbot
|
2
2
|
class Match < Struct.new(:reaction, :message)
|
3
|
+
include Cache
|
4
|
+
|
3
5
|
def matches?
|
4
|
-
|
6
|
+
matches_scope? && matches_place? && matches_regexp? && matches_sender? && matches_condition?
|
5
7
|
end
|
6
8
|
|
7
9
|
def invoke
|
8
|
-
Response.new(reaction, message).invoke(
|
10
|
+
Response.new(reaction, message).invoke(reaction_parameters)
|
9
11
|
end
|
10
12
|
|
11
13
|
protected
|
12
14
|
|
13
|
-
def
|
14
|
-
reaction.
|
15
|
+
def reaction_parameters
|
16
|
+
reaction.to_anything? ? [message.body] : match_data[1..-1]
|
15
17
|
end
|
16
18
|
|
17
19
|
def matches_regexp?
|
18
|
-
reaction.
|
20
|
+
reaction.to_anything? || !match_data.nil? || reaction.regexps.empty?
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
+
attr_cache :match_data do
|
24
|
+
reaction.regexps.inject(nil) do |result, regexp|
|
23
25
|
break result if result
|
24
26
|
message_text.match(regexp)
|
25
27
|
end
|
@@ -30,19 +32,29 @@ module Hipbot
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def matches_place?
|
33
|
-
reaction.
|
35
|
+
reaction.from_anywhere? || (message.room.nil? ? reaction.to_private_message? : matches_room?)
|
34
36
|
end
|
35
37
|
|
36
38
|
def matches_room?
|
37
|
-
reaction.
|
39
|
+
reaction.in_any_room? || reaction.rooms.include?(message.room.name)
|
38
40
|
end
|
39
41
|
|
40
42
|
def matches_sender?
|
41
43
|
reaction.from_all? || reaction.users.include?(message.sender.name)
|
42
44
|
end
|
43
45
|
|
46
|
+
def matches_condition?
|
47
|
+
reaction.condition.(*reaction.condition.parameters.map{ |parameter| message.send(parameter.last) })
|
48
|
+
end
|
49
|
+
|
44
50
|
def message_text
|
45
51
|
reaction.global? ? message.raw_body : message.body
|
46
52
|
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def invoke_all matches
|
56
|
+
matches.each(&:invoke)
|
57
|
+
end
|
58
|
+
end
|
47
59
|
end
|
48
60
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hipbot
|
2
|
+
module Matchable
|
3
|
+
def react sender, room, body
|
4
|
+
message = Message.new(body, room, sender)
|
5
|
+
matches = message_matches(message)
|
6
|
+
Match.invoke_all(matches)
|
7
|
+
end
|
8
|
+
|
9
|
+
def reactions
|
10
|
+
reaction_sets.flatten
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def reactables
|
16
|
+
plugins.map(&:class)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reaction_sets
|
20
|
+
reactables.each_with_object([]) do |reactable, array|
|
21
|
+
array.unshift(reactable.reactions)
|
22
|
+
array.push(reactable.default_reactions)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def message_matches message
|
27
|
+
reaction_sets.each do |reactions|
|
28
|
+
matches = reactions_matches(message, reactions)
|
29
|
+
return matches if matches.any?
|
30
|
+
end
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
34
|
+
def reactions_matches message, reactions
|
35
|
+
reactions.map{ |reaction| reaction.match_with(message) }.select(&:matches?)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/hipbot/message.rb
CHANGED
@@ -1,28 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
module Hipbot
|
2
3
|
class Message < Struct.new(:raw_body, :room, :sender)
|
3
|
-
|
4
|
+
include Cache
|
5
|
+
|
6
|
+
attr_accessor :body
|
7
|
+
|
8
|
+
MENTION_REGEXP = /@(\p{Word}++)/.freeze
|
4
9
|
|
5
10
|
def initialize *args
|
6
11
|
super
|
7
12
|
Hipbot.logger.info("MESSAGE from #{sender} in #{room}")
|
8
|
-
self.
|
9
|
-
self.
|
13
|
+
self.raw_body = raw_body.force_encoding('UTF-8')
|
14
|
+
self.body = strip_bot_mention
|
10
15
|
end
|
11
16
|
|
12
|
-
def for?
|
13
|
-
recipients.include?
|
17
|
+
def for? user
|
18
|
+
recipients.include? user.mention
|
14
19
|
end
|
15
20
|
|
16
|
-
|
17
|
-
|
21
|
+
attr_cache :recipients do
|
22
|
+
raw_body.scan(MENTION_REGEXP).flatten.compact.uniq
|
18
23
|
end
|
19
24
|
|
20
|
-
|
21
|
-
recipients
|
25
|
+
attr_cache :mentions do
|
26
|
+
recipients.tap{ |r| r.delete(bot_mention) }
|
22
27
|
end
|
23
28
|
|
24
29
|
def private?
|
25
30
|
room.nil?
|
26
31
|
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def bot_mention
|
36
|
+
Hipbot.user.mention
|
37
|
+
end
|
38
|
+
|
39
|
+
def strip_bot_mention
|
40
|
+
raw_body.gsub(/^@#{bot_mention}[^\p{Word}]*/, '')
|
41
|
+
end
|
27
42
|
end
|
28
43
|
end
|