hipbot 1.0.0 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef74572ebd12e87ab892010a3c8c0bae5b146584
4
- data.tar.gz: 03a8912f6c9958a88d3e2294844f6fc5fa5b7bc9
3
+ metadata.gz: ef69ec3d9ca84e1a5bf80f9e15d107b9e4bd2ec4
4
+ data.tar.gz: a875ec05d94328a7fb6a7c7f0dfbd3c207b4f6d9
5
5
  SHA512:
6
- metadata.gz: e8f9b8bd967a44c5b0b09057c63b257418f988a616e02cb63d91f55a26115f72da08ff3d82ead405ed48f38d7e24d8bf458bf6ed45d49bd16ab483c77d4e0bd2
7
- data.tar.gz: e174318fef49cc39dc116ce31057d5377a015c35989f4b2be9451fbb7737b98dae68f6de96bd1a2c8111be5dbaa245e61ae081f938a3bee1b43078e625a315ce
6
+ metadata.gz: d003c361dee535be8929fc219e16523ee02030383a9c607a119d4dad7fca9530feece39073119f32a0359d55b5ac67a7594dcfda44d8481a42d7d3371b1874eb
7
+ data.tar.gz: e5bf6173b705a247963f67c77e6b6d67d7c352cc1aee8c4f4d00ce709d7121d7d93b01422701509e6b6eb2fd7d603c7087b3b36f5cd87ed8cf8f753a030da184
@@ -3,6 +3,7 @@ rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
5
  - 2.0.0
6
+ - 2.1.0
6
7
  - jruby-19mode
7
8
  - rbx-19mode
8
9
  - jruby-head
data/Gemfile CHANGED
@@ -1,14 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rake'
4
- gem 'eventmachine'
5
- gem 'em-http-request'
6
- gem 'httparty'
7
- gem 'activesupport'
8
- gem 'daemons'
3
+ gemspec
9
4
  gem 'xmpp4r-hipchat', github: 'bartoszkopinski/xmpp4r-hipchat', branch: 'master'
10
5
 
11
- gem 'rspec'
12
- gem 'guard-rspec'
13
6
  gem 'coveralls', require: false
14
- gem 'mocha'
data/README.md CHANGED
@@ -373,6 +373,22 @@ end
373
373
  on /^My name is (.*)$/, :hello
374
374
  ```
375
375
 
376
+ ### Presence reaction
377
+ Use `on_presence` in the same way as `on` to make presence reactions:
378
+ ```ruby
379
+ class MyBot < Hipbot::Bot
380
+ # ...
381
+ on_presence do |status|
382
+ case status
383
+ when 'unavailable'
384
+ reply("Bye bye, #{sender.name}!")
385
+ when ''
386
+ reply("Welcome, #{sender.name}!")
387
+ end
388
+ end
389
+ end
390
+ ```
391
+
376
392
  ### Scopes
377
393
  Use `scope` blocks to extract common options:
378
394
  ```ruby
@@ -432,7 +448,7 @@ end
432
448
  ```
433
449
 
434
450
  ### User managment
435
- This behavior is experimental and not officially supported by HipChat. Bot must be an admin in order to perform this actions.
451
+ This behavior is experimental and not officially supported by HipChat. Bot must be an admin in order to perform these actions.
436
452
  ```ruby
437
453
  on /^kick (.*)/ do |user_name|
438
454
  user = Hipbot::User.find_by(name: user_name)
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # -*- encoding: utf-8 -*-
2
2
  require File.expand_path('../lib/hipbot/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
@@ -15,12 +15,12 @@ Gem::Specification.new do |gem|
15
15
  gem.name = "hipbot"
16
16
  gem.require_paths = ["lib"]
17
17
  gem.version = Hipbot::VERSION
18
- gem.add_runtime_dependency "xmpp4r-hipchat", [">= 0.0.3"]
19
- gem.add_runtime_dependency "daemons", [">= 1.1.8"]
20
- gem.add_runtime_dependency "activesupport", [">= 3.2.12"]
21
- gem.add_runtime_dependency "eventmachine", [">= 1.0.3"]
22
- gem.add_runtime_dependency "em-http-request", [">= 1.0.3"]
23
- gem.add_development_dependency "rspec", ['~> 2.13.0']
24
- gem.add_development_dependency "guard-rspec", ['~> 2.5.1']
25
- gem.add_development_dependency "mocha", ['~> 0.13.3']
18
+ gem.add_runtime_dependency "xmpp4r-hipchat", ["= 0.0.4"]
19
+ gem.add_runtime_dependency "daemons", ["~> 1.1"]
20
+ gem.add_runtime_dependency "activesupport", [">= 3.0.0"]
21
+ gem.add_runtime_dependency "eventmachine", ["~> 1.0"]
22
+ gem.add_runtime_dependency "em-http-request", ["~> 1.1"]
23
+ gem.add_development_dependency "rake"
24
+ gem.add_development_dependency "rspec"
25
+ gem.add_development_dependency "guard-rspec"
26
26
  end
@@ -40,6 +40,7 @@ require 'hipbot/match'
40
40
  require 'hipbot/message'
41
41
  require 'hipbot/reaction'
42
42
  require 'hipbot/response'
43
+ require 'hipbot/presence'
43
44
  require 'hipbot/room'
44
45
  require 'hipbot/user'
45
46
  require 'hipbot/version'
@@ -47,7 +47,7 @@ module Hipbot
47
47
  user.update_attributes(user_data)
48
48
 
49
49
  if user.attributes['email'].nil?
50
- # user.update_attributes(client.get_user_details(user.id))
50
+ user.update_attributes(client.get_user_details(user.id))
51
51
  end
52
52
  user.id
53
53
  end
@@ -15,10 +15,13 @@ module Hipbot
15
15
  def handle_room_presence
16
16
  with_room(id: room_id) do |room|
17
17
  with_user(name: user_name) do |user|
18
+ Hipbot.react_to_presence(user, presence, room)
18
19
  if offline_presence?
19
20
  room.on_leave(user)
20
21
  elsif online_presence? && !room.users.include?(user)
21
22
  room.on_join(user)
23
+ else
24
+ # TODO: Availability status change handling
22
25
  end
23
26
  end
24
27
  end
@@ -8,7 +8,10 @@ module Hipbot
8
8
 
9
9
  def initialize
10
10
  self.adapter = Adapters::Hipchat
11
- self.exception_handler = Proc.new{ |e| Hipbot.logger.error(e) }
11
+ self.exception_handler = Proc.new do |e|
12
+ Hipbot.logger.error(e.message)
13
+ e.backtrace.each { |line| Hipbot.logger.error(line) }
14
+ end
12
15
  self.helpers = Module.new
13
16
  self.jid = ''
14
17
  self.join = :all
@@ -2,7 +2,7 @@ module Hipbot
2
2
  module Helpers
3
3
  [:get, :post, :put, :delete].each do |method|
4
4
  define_method method do |url, query = {}, &block|
5
- Http::Request.new(url, query, method).(&block)
5
+ Http::Request.new(url, query, method).call(&block)
6
6
  end
7
7
  module_function method
8
8
  end
@@ -1,17 +1,13 @@
1
- # encoding: utf-8
2
1
  module Hipbot
3
2
  module Http
4
- class Request < Struct.new(:url, :params, :method)
3
+ class Request < Struct.new(:url, :query, :method)
5
4
  DEFAULT_HEADERS = { 'accept-encoding' => 'gzip, compressed' }.freeze
6
5
  CONNECTION_SETTINGS = { connect_timeout: 5, inactivity_timeout: 10 }.freeze
7
6
  ERROR_CALLBACK = ->(error){ Hipbot.logger.error(error) }
8
7
 
9
8
  def initialize *args
10
9
  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}")
10
+ Hipbot.logger.info("HTTP-REQUEST: #{url} #{query}")
15
11
  end
16
12
 
17
13
  def call &success_block
@@ -29,12 +25,12 @@ module Hipbot
29
25
  instance_exec(e, &Hipbot.exception_handler)
30
26
  end
31
27
 
32
- def http options = {}
33
- @http ||= connection.send(method, params.merge(options))
28
+ def http
29
+ @http ||= connection.send(method, query: query.merge(head: DEFAULT_HEADERS))
34
30
  end
35
31
 
36
32
  def connection
37
- @connection ||= EM::HttpRequest.new(url, CONNECTION_SETTINGS)
33
+ EM::HttpRequest.new(url, CONNECTION_SETTINGS)
38
34
  end
39
35
  end
40
36
 
@@ -57,7 +53,6 @@ module Hipbot
57
53
  end
58
54
 
59
55
  def json
60
- binding.pry
61
56
  @json ||= JSON.parse(body) || {}
62
57
  end
63
58
  end
@@ -2,10 +2,8 @@ require 'logger'
2
2
 
3
3
  module Hipbot
4
4
  class Logger < ::Logger
5
- def add(severity, message = nil, progname = nil, &block)
6
- msg = message || (block_given? and block.call) || progname
7
- severity_name = { 0 => "DEBUG", 1 => "INFO", 2 => "WARN", 3 => "ERROR", 4 => "FATAL", 5 => "UNKNOWN" }[severity]
8
- super(severity, "[#{severity_name}][#{Time.now}] #{msg}")
5
+ def format_message(severity, timestamp, progname, msg)
6
+ "[#{severity}][#{Time.now}] #{msg}\n"
9
7
  end
10
8
  end
11
9
  end
@@ -28,7 +28,7 @@ module Hipbot
28
28
  end
29
29
 
30
30
  def matches_scope?
31
- reaction.global? || message.for?(Hipbot.user) || message.private?
31
+ reaction.global? || message.private? || message.for?(Hipbot.user)
32
32
  end
33
33
 
34
34
  def matches_place?
@@ -44,7 +44,7 @@ module Hipbot
44
44
  end
45
45
 
46
46
  def matches_condition?
47
- reaction.condition.(*reaction.condition.parameters.map{ |parameter| message.send(parameter.last) })
47
+ reaction.condition.call(*reaction.condition.parameters.map{ |parameter| message.send(parameter.last) })
48
48
  end
49
49
 
50
50
  def message_text
@@ -2,7 +2,13 @@ module Hipbot
2
2
  module Matchable
3
3
  def react sender, room, body
4
4
  message = Message.new(body, room, sender)
5
- matches = message_matches(message)
5
+ matches = set_matches(reaction_sets, message)
6
+ Match.invoke_all(matches)
7
+ end
8
+
9
+ def react_to_presence sender, status, room
10
+ presence = Presence.new(sender, status, room)
11
+ matches = set_matches(presence_reaction_sets, presence)
6
12
  Match.invoke_all(matches)
7
13
  end
8
14
 
@@ -16,6 +22,10 @@ module Hipbot
16
22
  plugins.map(&:class)
17
23
  end
18
24
 
25
+ def presence_reaction_sets
26
+ reactables.map(&:presence_reactions)
27
+ end
28
+
19
29
  def reaction_sets
20
30
  reactables.each_with_object([]) do |reactable, array|
21
31
  array.unshift(reactable.reactions)
@@ -23,16 +33,16 @@ module Hipbot
23
33
  end
24
34
  end
25
35
 
26
- def message_matches message
27
- reaction_sets.each do |reactions|
36
+ def set_matches sets, message
37
+ sets.each do |reactions|
28
38
  matches = reactions_matches(message, reactions)
29
39
  return matches if matches.any?
30
40
  end
31
41
  []
32
42
  end
33
43
 
34
- def reactions_matches message, reactions
35
- reactions.map{ |reaction| reaction.match_with(message) }.select(&:matches?)
44
+ def reactions_matches matchable, reactions
45
+ reactions.map{ |reaction| reaction.match_with(matchable) }.select(&:matches?)
36
46
  end
37
47
  end
38
48
  end
@@ -0,0 +1,17 @@
1
+ module Hipbot
2
+ class Presence < Struct.new(:sender, :body, :room)
3
+
4
+ def initialize *args
5
+ super
6
+ Hipbot.logger.info("PRESENCE from #{sender} in #{room}")
7
+ end
8
+
9
+ def for? _
10
+ true
11
+ end
12
+
13
+ def private?
14
+ room.nil?
15
+ end
16
+ end
17
+ end
@@ -2,11 +2,17 @@ module Hipbot
2
2
  module Reactable
3
3
  include Cache
4
4
 
5
- attr_cache :reactions, :default_reactions, :options_stack
5
+ attr_cache :reactions, :default_reactions, :presence_reactions, :options_stack
6
6
  attr_cache :reaction_factory do
7
7
  ReactionFactory.new(self)
8
8
  end
9
9
 
10
+ def on_presence *params, &block
11
+ scope *params do
12
+ presence_reactions << to_reaction(block)
13
+ end
14
+ end
15
+
10
16
  def on *params, &block
11
17
  scope *params do
12
18
  reactions << to_reaction(block)
@@ -71,7 +71,7 @@ module Hipbot
71
71
  protected
72
72
 
73
73
  def replace_symbols values, replacements_hash
74
- Array(values).flat_map{ |v| replacements_hash[v] || v }.uniq
74
+ Array(values).flat_map{ |v| replacements_hash[v] || v }.map(&:to_s)
75
75
  end
76
76
  end
77
77
  end
@@ -77,12 +77,12 @@ module Hipbot
77
77
  end
78
78
  end
79
79
 
80
- # protected
80
+ protected
81
81
 
82
- # def method_missing name, *args, &block
83
- # return all.public_send(name, *args, &block) if Array.instance_methods.include?(name)
84
- # super
85
- # end
82
+ def method_missing name, *args, &block
83
+ return all.public_send(name, *args, &block) if Array.instance_methods.include?(name)
84
+ super
85
+ end
86
86
  end
87
87
  end
88
88
  end
@@ -15,9 +15,5 @@ module Hipbot
15
15
  def myself?
16
16
  self == Hipbot.user
17
17
  end
18
-
19
- def guest?
20
- attributes[:role] == 'visitor'
21
- end
22
18
  end
23
19
  end
@@ -1,3 +1,3 @@
1
1
  module Hipbot
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -44,10 +44,6 @@ class CoolPlugin
44
44
  on /respond cool/ do
45
45
  reply('cool responded')
46
46
  end
47
-
48
- default do
49
- reply("I didn't understand you")
50
- end
51
47
  end
52
48
 
53
49
  class MyHipbot < Hipbot::Bot
@@ -63,6 +59,19 @@ class MyHipbot < Hipbot::Bot
63
59
  reply('What do you mean, Other Guy?')
64
60
  end
65
61
 
62
+ default do
63
+ reply("I didn't understand you")
64
+ end
65
+
66
+ on_presence do |status|
67
+ case status
68
+ when :available
69
+ reply("Welcome, #{sender.name}!")
70
+ when :unavailable
71
+ reply("Bye bye, #{sender.name}!")
72
+ end
73
+ end
74
+
66
75
  desc 'greets the user'
67
76
  on /^hello hipbot!$/ do
68
77
  reply('hello!')
@@ -20,145 +20,152 @@ describe MyHipbot do
20
20
  end
21
21
  end
22
22
 
23
+ describe 'presence reactions' do
24
+ it 'greets joining user', focus: true do
25
+ subject.should_receive(:send_to_room).with(room, 'Welcome, John Doe!')
26
+ subject.react_to_presence(sender, :available, room)
27
+ end
28
+ end
29
+
23
30
  describe 'replying' do
24
31
  it 'should reply to hello' do
25
- subject.expects(:send_to_room).with(room, 'hello!')
32
+ subject.should_receive(:send_to_room).with(room, 'hello!')
26
33
  subject.react(sender, room, '@robot hello hipbot!')
27
34
  end
28
35
 
29
36
  it 'should reply with argument' do
30
- subject.expects(:send_to_room).with(room, "I know I'm cool")
37
+ subject.should_receive(:send_to_room).with(room, "I know I'm cool")
31
38
  subject.react(sender, room, '@robot you\'re cool, robot')
32
39
  end
33
40
 
34
41
  it 'should reply to global message' do
35
- subject.expects(:send_to_room).with(room, 'hello!')
42
+ subject.should_receive(:send_to_room).with(room, 'hello!')
36
43
  subject.react(sender, room, 'hi everyone!')
37
44
  end
38
45
 
39
46
  it 'should respond with default reply' do
40
- subject.expects(:send_to_room).with(room, "I didn't understand you")
47
+ subject.should_receive(:send_to_room).with(room, "I didn't understand you")
41
48
  subject.react(sender, room, '@robot blahlblah')
42
49
  end
43
50
  end
44
51
 
45
52
  describe '"from" option' do
46
53
  it 'reacts to sender from required team' do
47
- subject.expects(:send_to_room).with(room, 'restarting')
54
+ subject.should_receive(:send_to_room).with(room, 'restarting')
48
55
  subject.react(sender, room, '@robot restart')
49
56
  end
50
57
 
51
58
  it 'ignores sender when not in team' do
52
- subject.expects(:send_to_room).with(room, 'What do you mean, Other Guy?')
59
+ subject.should_receive(:send_to_room).with(room, 'What do you mean, Other Guy?')
53
60
  subject.react(other_sender, room, '@robot restart')
54
61
  end
55
62
  end
56
63
 
57
64
  describe '"room" option' do
58
65
  it 'reacts in required room' do
59
- subject.expects(:send_to_room).with(room, 'deploying')
66
+ subject.should_receive(:send_to_room).with(room, 'deploying')
60
67
  subject.react(sender, room, '@robot deploy')
61
68
  end
62
69
 
63
70
  it 'ignores other rooms' do
64
- subject.expects(:send_to_room).with(other_room, "I didn't understand you")
71
+ subject.should_receive(:send_to_room).with(other_room, "I didn't understand you")
65
72
  subject.react(sender, other_room, '@robot deploy')
66
73
  end
67
74
  end
68
75
 
69
76
  describe 'room=true' do
70
77
  it 'reacts in any room' do
71
- subject.expects(:send_to_room).with(room, 'doing room thing')
78
+ subject.should_receive(:send_to_room).with(room, 'doing room thing')
72
79
  subject.react(sender, room, '@robot room thing')
73
80
  end
74
81
 
75
82
  it 'ignores room commands if not in room' do
76
- subject.expects(:send_to_user).with(sender, "I didn't understand you")
83
+ subject.should_receive(:send_to_user).with(sender, "I didn't understand you")
77
84
  subject.react(sender, nil, 'room thing')
78
85
  end
79
86
  end
80
87
 
81
88
  describe 'room=false' do
82
89
  it 'ignores private command in room' do
83
- subject.expects(:send_to_room).with(room, "I didn't understand you")
90
+ subject.should_receive(:send_to_room).with(room, "I didn't understand you")
84
91
  subject.react(sender, room, '@robot private thing')
85
92
  end
86
93
 
87
94
  it 'allows private command if not in room' do
88
- subject.expects(:send_to_user).with(sender, 'doing private thing')
95
+ subject.should_receive(:send_to_user).with(sender, 'doing private thing')
89
96
  subject.react(sender, nil, 'private thing')
90
97
  end
91
98
  end
92
99
 
93
100
  describe 'scope' do
94
101
  it 'sets its attributes to every reaction inside' do
95
- subject.expects(:send_to_room).with(room, 'doing John Doe thing')
102
+ subject.should_receive(:send_to_room).with(room, 'doing John Doe thing')
96
103
  subject.react(sender, room, '@robot John Doe thing')
97
104
  end
98
105
 
99
106
  it 'does not match other senders' do
100
- subject.expects(:send_to_room).with(room, 'What do you mean, Other Guy?')
107
+ subject.should_receive(:send_to_room).with(room, 'What do you mean, Other Guy?')
101
108
  subject.react(other_sender, room, '@robot John Doe thing')
102
109
  end
103
110
 
104
111
  it 'merges params if embedded' do
105
- subject.expects(:send_to_room).with(room, 'doing John Doe project thing')
112
+ subject.should_receive(:send_to_room).with(room, 'doing John Doe project thing')
106
113
  subject.react(sender, room, '@robot John Doe project thing')
107
114
  end
108
115
 
109
116
  it 'ignores message from same sander in other room' do
110
- subject.expects(:send_to_room).with(other_room, "I didn't understand you")
117
+ subject.should_receive(:send_to_room).with(other_room, "I didn't understand you")
111
118
  subject.react(sender, other_room, '@robot John Doe project thing')
112
119
  end
113
120
 
114
121
  it 'ignores message from other sender in same room' do
115
- subject.expects(:send_to_room).with(room, 'What do you mean, Other Guy?')
122
+ subject.should_receive(:send_to_room).with(room, 'What do you mean, Other Guy?')
116
123
  subject.react(other_sender, room, '@robot John Doe project thing')
117
124
  end
118
125
  end
119
126
 
120
127
  describe 'custom helpers' do
121
128
  it 'should have access to room variable' do
122
- subject.expects(:send_to_room).with(room, 'Project: Project 1')
129
+ subject.should_receive(:send_to_room).with(room, 'Project: Project 1')
123
130
  subject.react(sender, room, '@robot tell me the project name')
124
131
  end
125
132
 
126
133
  it 'should have access to message variable' do
127
- subject.expects(:send_to_room).with(room, 'you are John')
134
+ subject.should_receive(:send_to_room).with(room, 'you are John')
128
135
  subject.react(sender, room, '@robot tell me my name')
129
136
  end
130
137
  end
131
138
 
132
139
  describe 'plugins' do
133
140
  it 'should reply to reaction defined in plugin' do
134
- subject.expects(:send_to_room).with(room, 'awesome responded')
141
+ subject.should_receive(:send_to_room).with(room, 'awesome responded')
135
142
  subject.react(sender, room, '@robot respond awesome')
136
143
  end
137
144
 
138
145
  it 'should reply to reaction defined in second plugin' do
139
- subject.expects(:send_to_room).with(room, 'cool responded')
146
+ subject.should_receive(:send_to_room).with(room, 'cool responded')
140
147
  subject.react(sender, room, '@robot respond cool')
141
148
  end
142
149
  end
143
150
 
144
151
  describe 'method reaction' do
145
152
  it 'should reply to a method reaction defined in plugin' do
146
- subject.expects(:send_to_room).with(room, 'parameter: empty')
153
+ subject.should_receive(:send_to_room).with(room, 'parameter: empty')
147
154
  subject.react(sender, room, '@robot method reaction')
148
155
  end
149
156
 
150
157
  it 'should reply to a method reaction defined in plugin with parameters' do
151
- subject.expects(:send_to_room).with(room, 'parameter: method param')
158
+ subject.should_receive(:send_to_room).with(room, 'parameter: method param')
152
159
  subject.react(sender, room, '@robot method reaction method param')
153
160
  end
154
161
 
155
162
  it 'should reply to a scope method reaction defined in plugin' do
156
- subject.expects(:send_to_room).with(room, 'scope method reaction')
163
+ subject.should_receive(:send_to_room).with(room, 'scope method reaction')
157
164
  subject.react(sender, room, '@robot scope method reaction')
158
165
  end
159
166
 
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')
167
+ it 'should reply to a scope regexp with method reaction defined in plugin' do
168
+ subject.should_receive(:send_to_room).with(room, 'parameter: empty')
162
169
  subject.react(sender, room, '@robot scope regexp')
163
170
  end
164
171
  end