boty 0.1.0 → 0.1.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +18 -1
  5. data/README.md +39 -3
  6. data/Rakefile +1 -1
  7. data/boty.gemspec +9 -5
  8. data/lib/boty.rb +2 -1
  9. data/lib/boty/action.rb +26 -35
  10. data/lib/boty/action_description.rb +24 -0
  11. data/lib/boty/bot.rb +36 -25
  12. data/lib/boty/dsl.rb +3 -3
  13. data/lib/boty/eventable.rb +4 -3
  14. data/lib/boty/http.rb +3 -4
  15. data/lib/boty/locale.rb +12 -13
  16. data/lib/boty/logger.rb +14 -3
  17. data/lib/boty/rspec.rb +15 -16
  18. data/lib/boty/session.rb +7 -8
  19. data/lib/boty/slack.rb +11 -3
  20. data/lib/boty/slack/channel.rb +2 -1
  21. data/lib/boty/slack/chat.rb +5 -1
  22. data/lib/boty/slack/rtm.rb +1 -1
  23. data/lib/boty/slack/url.rb +10 -5
  24. data/lib/boty/slack/user.rb +2 -1
  25. data/lib/boty/slack/users.rb +1 -1
  26. data/lib/boty/version.rb +1 -1
  27. data/script/knows.rb +10 -9
  28. data/script/pug.rb +5 -1
  29. data/spec/boty/bot_spec.rb +89 -72
  30. data/spec/boty/cli_spec.rb +5 -5
  31. data/spec/boty/dsl_spec.rb +12 -13
  32. data/spec/boty/rspec_spec.rb +2 -1
  33. data/spec/boty/script_loader_spec.rb +8 -6
  34. data/spec/boty/session_spec.rb +2 -2
  35. data/spec/boty/slack/chat_spec.rb +18 -18
  36. data/spec/boty/slack/im_spec.rb +4 -4
  37. data/spec/boty/slack/message_spec.rb +11 -9
  38. data/spec/boty/slack/rtm_spec.rb +3 -3
  39. data/spec/boty/slack/url_spec.rb +5 -5
  40. data/spec/boty/slack/users_spec.rb +23 -23
  41. data/spec/happy_path_spec.rb +19 -18
  42. data/spec/script/i18n_spec.rb +18 -10
  43. data/spec/script/knows_spec.rb +8 -7
  44. data/spec/script/pug_spec.rb +27 -10
  45. data/spec/script/remember_spec.rb +27 -21
  46. data/spec/spec_helper.rb +4 -3
  47. data/spec/support/em_support.rb +1 -3
  48. data/spec/support/faraday_support.rb +0 -1
  49. data/spec/support/faye_support.rb +9 -6
  50. data/spec/support/file_system_matchers.rb +4 -4
  51. data/spec/support/logger_support.rb +9 -12
  52. data/spec/support/session_support.rb +26 -15
  53. data/spec/support/slack_support.rb +9 -6
  54. data/spec/support/template_project_support.rb +24 -23
  55. data/spec/support/thor_support.rb +3 -3
  56. data/template/project/%bot_name%.rb +4 -1
  57. data/template/project/spec/spec_helper.rb +4 -2
  58. metadata +21 -4
@@ -6,7 +6,8 @@ module Boty
6
6
  end
7
7
 
8
8
  def event(data)
9
- return unless type = event_type(data)
9
+ type = event_type data
10
+ return unless type
10
11
 
11
12
  events[type].each do |action|
12
13
  action.call data
@@ -30,9 +31,9 @@ module Boty
30
31
 
31
32
  def event_type(data)
32
33
  type = data["type"].to_sym
33
- logger.debug { "event[#{type}] arrived: #{data}" }
34
+ logger.debug do "event[#{type}] arrived: #{data}" end
34
35
  unless events[type]
35
- logger.debug "no action binded to #{type}"
36
+ logger.debug do "no action binded to #{type}" end
36
37
  return
37
38
  end
38
39
  type
@@ -13,17 +13,16 @@ module Boty
13
13
 
14
14
  def connection(verb, url, params)
15
15
  uri = URI url
16
- Faraday.new(url: "#{uri.scheme}://#{uri.host}") { |builder|
16
+ faraday = Faraday.new(url: "#{uri.scheme}://#{uri.host}") { |builder|
17
17
  builder.adapter(*Faraday.default_adapter)
18
- }.public_send(verb) { |req|
19
- req.url uri.path, params
20
18
  }
19
+ faraday.public_send(verb) { |req| req.url uri.path, params }
21
20
  end
22
21
 
23
22
  def handle_response
24
23
  # TODO: use a response parser accordingly to the
25
24
  body = response.body
26
- if /application\/json/.match response.headers["Content-Type"]
25
+ if %r{application/json}.match response.headers["Content-Type"]
27
26
  JSON.parse body
28
27
  else
29
28
  body
@@ -1,24 +1,23 @@
1
1
  module Boty
2
2
  class Locale
3
- def self.reload(locale = nil)
4
- _locale = new
5
- I18n.load_path = _locale.locales_paths.uniq
3
+ def self.reload(language = nil)
4
+ locale = new
5
+ I18n.load_path = locale.locales_paths.uniq
6
6
  I18n.available_locales = I18n::Backend::Simple.new.available_locales
7
- _locale.set_locale locale if locale
7
+ locale.locale = language if language
8
8
  end
9
9
 
10
10
  def locales_paths
11
- default_locales_path = File.expand_path("../../../locale/**/*.yml", __FILE__)
12
- (Dir["locale/**/*.yml"] + Dir[default_locales_path]).
13
- map { |file| File.expand_path file }
11
+ locale_yaml_files_path = "../../../locale/**/*.yml"
12
+ default_locales_path = File.expand_path(locale_yaml_files_path, __FILE__)
13
+ (Dir["locale/**/*.yml"] + Dir[default_locales_path])
14
+ .map { |file| File.expand_path file }
14
15
  end
15
16
 
16
- def set_locale(locale)
17
- begin
18
- I18n.locale = locale
19
- rescue I18n::InvalidLocale
20
- I18n.locale = :en
21
- end
17
+ def locale=(language)
18
+ I18n.locale = language
19
+ rescue I18n::InvalidLocale
20
+ I18n.locale = :en
22
21
  end
23
22
  end
24
23
  end
@@ -17,6 +17,16 @@ module Boty
17
17
  Logger.adapter
18
18
  end
19
19
 
20
+ def log_error(error, message)
21
+ logger.error do
22
+ "#{message}\n#{error.message}"
23
+ end
24
+
25
+ logger.debug do
26
+ error.backtrace.reduce("") { |a, e| a << "#{e}\n" }
27
+ end
28
+ end
29
+
20
30
  class Multi < ::Logger
21
31
  def initialize(adapters)
22
32
  @adapters = adapters
@@ -38,7 +48,7 @@ module Boty
38
48
  class Memory < ::Logger
39
49
  attr_reader :logs
40
50
 
41
- def initialize(*args)
51
+ def initialize(*)
42
52
  @logs = []
43
53
  end
44
54
 
@@ -52,8 +62,9 @@ module Boty
52
62
  end
53
63
 
54
64
  class Null < ::Logger
55
- def initialize(*args); end
56
- def add(*args, &block); end
65
+ def initialize(*); end
66
+
67
+ def add(*, &block); end
57
68
  end
58
69
  end
59
70
  end
@@ -8,23 +8,22 @@ module Boty
8
8
  include SlackSupport::Users
9
9
 
10
10
  before do
11
- @_bot = Boty::Bot.new(
12
- {"id" => "1234", "name" => "bot"}
13
- )
14
-
15
- class << Boty::Slack.chat
16
- attr_accessor :messages
17
-
18
- def post_message(message, options)
19
- @messages ||= []
20
- @messages << { message: message, options: options }
21
- end
22
- end
11
+ @_bot = Boty::Bot.new("id" => "1234", "name" => "bot")
12
+ mock_post_message
23
13
  end
24
14
 
25
- let(:bot) {
26
- Boty::DSL.new @_bot
27
- }
15
+ let(:bot) { Boty::DSL.new @_bot }
16
+ end
17
+ end
18
+
19
+ def mock_post_message
20
+ class << Boty::Slack.chat
21
+ attr_accessor :messages
22
+
23
+ def post_message(message, options)
24
+ @messages ||= []
25
+ @messages << { message: message, options: options }
26
+ end
28
27
  end
29
28
  end
30
29
 
@@ -39,7 +38,7 @@ module Boty
39
38
 
40
39
  ::RSpec::Matchers.define :have_responded do |expected|
41
40
  # TODO: add proper messages for failures.
42
- match do |dsl|
41
+ match do
43
42
  last_message = Slack.chat.messages.last
44
43
  expected == last_message[:message]
45
44
  end
@@ -22,38 +22,37 @@ module Boty
22
22
  begin
23
23
  on_message event, @bot
24
24
  rescue StandardError => e
25
- logger.error "Message #{event} could not be processed. #{e.message}"
26
- logger.debug e.backtrace.reduce("") { |msg, line| msg << "#{line}\n" }
25
+ log_error e, "Message #{event} could not be processed."
27
26
  end
28
27
  end
29
28
  end
30
29
 
31
30
  def login
32
- logger.debug { "Logging in against slack right now" }
31
+ logger.debug do "Logging in against slack right now" end
33
32
  @slack_info = Slack.rtm.start
34
- logger.debug { "yep! logged in!" }
33
+ logger.debug do "yep! logged in!" end
35
34
  @session_url = @slack_info["url"]
36
35
  end
37
36
 
38
37
  def initialize_bot(&block)
39
38
  Bot.new(@slack_info["self"]).tap { |bot|
40
39
  DSL.new(bot).instance_eval(&block) if block_given?
41
- logger.debug { "Bot is configured and ready to go!" }
40
+ logger.debug do "Bot is configured and ready to go!" end
42
41
  }
43
42
  end
44
43
 
45
44
  def on_message(event, bot)
46
- logger.debug { "Message arrived. Creating bot event" }
45
+ logger.debug do "Message arrived. Creating bot event" end
47
46
  bot.event JSON.parse(event.data)
48
47
  end
49
48
 
50
49
  def on_close
51
50
  logger.debug { "bye bye" }
52
- #todo try to reconnect (stablish_connection) unless is an em interrupt
51
+ # TODO: try to reconnect (stablish_connection) unless is an em interrupt
53
52
  end
54
53
 
55
54
  def stablish_connection
56
- logger.debug { "Starting to listen on #{@session_url}" }
55
+ logger.debug do "Starting to listen on #{@session_url}" end
57
56
  ws = Faye::WebSocket::Client.new @session_url
58
57
  ws.on :close do on_close end
59
58
  on_connect ws
@@ -10,9 +10,17 @@ require "boty/slack/message"
10
10
  module Boty
11
11
  module Slack
12
12
  class << self
13
- def chat; @chat ||= Chat.new end
14
- def rtm; @rtm ||= RTM.new end
15
- def users; @users ||= Users.new end
13
+ def chat
14
+ @chat ||= Chat.new
15
+ end
16
+
17
+ def rtm
18
+ @rtm ||= RTM.new
19
+ end
20
+
21
+ def users
22
+ @users ||= Users.new
23
+ end
16
24
  end
17
25
 
18
26
  def User(user_id)
@@ -4,7 +4,8 @@ module Boty
4
4
  attr_accessor :id
5
5
 
6
6
  def initialize(id:, info:)
7
- @id, @info = id, info
7
+ @id = id
8
+ @info = info
8
9
  end
9
10
  end
10
11
  end
@@ -4,7 +4,11 @@ module Boty
4
4
  include Slack::URL
5
5
  url "https://slack.com/api/chat.postMessage"
6
6
 
7
- def im; @im ||= IM.new end
7
+ attr_reader :im
8
+
9
+ def initialize
10
+ @im = IM.new
11
+ end
8
12
 
9
13
  def post_message(message, parameters = {})
10
14
  defaults = {
@@ -2,7 +2,7 @@ module Boty
2
2
  module Slack
3
3
  class RTM
4
4
  include Slack::URL
5
- url "https://#{ENV["SLACK_COMPANY"]}.slack.com/api/"
5
+ url "https://#{ENV['SLACK_COMPANY']}.slack.com/api/"
6
6
 
7
7
  def start(parameters = {})
8
8
  defaults = { simple_latest: true, no_unreads: true }
@@ -2,9 +2,14 @@ module Boty
2
2
  module Slack
3
3
  module URL
4
4
  def self.included(base)
5
+ class << base
6
+ attr_reader :_url
7
+ end
8
+
5
9
  base.instance_eval do
6
- def url(url); @_url = url end
7
- def _url; @_url end
10
+ def url(url)
11
+ @_url = url
12
+ end
8
13
  end
9
14
  end
10
15
 
@@ -16,11 +21,11 @@ module Boty
16
21
 
17
22
  def parameterize(user_parameters, path: nil)
18
23
  url = path ? self.class._url + path : self.class._url
19
- parameters = {token: ENV["SLACK_BOT_API_TOKEN"]}.merge user_parameters
20
- parameters.reduce(url + "?") { |_url, param|
24
+ parameters = { token: ENV["SLACK_BOT_API_TOKEN"] }.merge user_parameters
25
+ parameters.reduce(url + "?") { |final_url, param|
21
26
  parameter = param[0]
22
27
  value = URI.encode param[1].to_s
23
- "#{_url}#{parameter}=#{value}&"
28
+ "#{final_url}#{parameter}=#{value}&"
24
29
  }.gsub(/&$/, "")
25
30
  end
26
31
  end
@@ -4,7 +4,8 @@ module Boty
4
4
  attr_accessor :id, :name
5
5
 
6
6
  def initialize(info)
7
- @id, @name = info["id"], info["name"]
7
+ @id = info["id"]
8
+ @name = info["name"]
8
9
  end
9
10
  end
10
11
  end
@@ -21,7 +21,7 @@ module Boty
21
21
  end
22
22
 
23
23
  def by_name(name)
24
- list.select { |user| user.name == name }.first
24
+ list.find { |user| user.name == name }
25
25
  end
26
26
  end
27
27
  end
@@ -1,3 +1,3 @@
1
1
  module Boty
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -6,25 +6,26 @@ end
6
6
  class KnownFormmater
7
7
  def initialize(actions)
8
8
  @actions = actions
9
- @max_size = @actions.keys.map(&:length).max
9
+ @descriptions = @actions.map(&:desc)
10
+ @max_size = @descriptions.map(&:command).map(&:length).max
10
11
  end
11
12
 
12
13
  def format
13
- @actions.inject("```\n") { |_message, command|
14
- _message << format_command(command) + "\n"
14
+ @descriptions.inject("```\n") { |message, description|
15
+ message << format_description(description) + "\n"
15
16
  } + "```"
16
17
  end
17
18
 
18
19
  private
19
20
 
20
- def name(command_name)
21
- pad = @max_size - command_name.length
22
- (" " * pad) + command_name
21
+ def name(trigger)
22
+ pad = @max_size - trigger.length
23
+ (" " * pad) + trigger
23
24
  end
24
25
 
25
- def format_command(command)
26
- message = name command.first
27
- message << ": #{command.last}" if command.last
26
+ def format_description(description)
27
+ message = name description.command
28
+ message << ": #{description.description}" if description.description
28
29
  message
29
30
  end
30
31
  end
@@ -1,12 +1,16 @@
1
1
  desc "pug me", I18n.t("scripts.pug_me")
2
2
  command(/pug me/i) do
3
3
  response = http.get "http://pugme.herokuapp.com/random"
4
- say "<#{response["pug"]}>"
4
+ say "<#{response['pug']}>"
5
5
  end
6
6
 
7
7
  desc "pug bomb X", I18n.t("scripts.pug_bomb")
8
8
  command(/pug bomb( \d+)?/i) do |count|
9
9
  count = (count || "5").strip
10
+ if count.to_i > 5
11
+ count = "5"
12
+ say "wow! so many pugs! sendind 5 instead."
13
+ end
10
14
  response = http.get "http://pugme.herokuapp.com/bomb", count: count
11
15
  response["pugs"].each do |pug| say "<#{pug}>" end
12
16
  end
@@ -1,11 +1,14 @@
1
1
  module Boty
2
2
  RSpec.describe Bot do
3
+ include Boty
3
4
  subject(:bot) { described_class.new bot_info }
4
5
 
5
- let(:bot_info) {{
6
- "id" => "666",
7
- "name" => "jabber"
8
- }}
6
+ let(:bot_info) do
7
+ {
8
+ "id" => "666",
9
+ "name" => "jabber"
10
+ }
11
+ end
9
12
 
10
13
  describe "#on" do
11
14
  it "binds an event `'type'` to a block" do
@@ -22,18 +25,20 @@ module Boty
22
25
  end
23
26
 
24
27
  describe "#off" do
25
- let(:data) {{
26
- "type" => "bbq",
27
- "text" => "omg. wtf."
28
- }}
28
+ let(:data) do
29
+ {
30
+ "type" => "bbq",
31
+ "text" => "omg. wtf."
32
+ }
33
+ end
29
34
 
30
35
  it "unbounds an event by type AND block, just if the block is the same" do
31
36
  @permanent_executed = false
32
- permanent_block = ->(_){ @permanent_executed = true }
37
+ permanent_block = ->(_) do @permanent_executed = true end
33
38
  bot.on :bbq, &permanent_block
34
39
 
35
40
  @ephemeral_executed = false
36
- ephemeral_block = ->(_){ @ephemeral_executed = true }
41
+ ephemeral_block = ->(_) do @ephemeral_executed = true end
37
42
  bot.on :bbq, &ephemeral_block
38
43
  bot.off :bbq, &ephemeral_block
39
44
 
@@ -45,9 +50,9 @@ module Boty
45
50
 
46
51
  it "unbounds all events by type" do
47
52
  @first_block = @second_block = @third_block = false
48
- bot.on(:bbq) { |_| @first_block = true }
49
- bot.on(:bbq) { |_| @second_block = true }
50
- bot.on(:bbq) { |_| @third_block = true }
53
+ bot.on(:bbq) do |_| @first_block = true end
54
+ bot.on(:bbq) do |_| @second_block = true end
55
+ bot.on(:bbq) do |_| @third_block = true end
51
56
  bot.off(:bbq)
52
57
 
53
58
  bot.event data
@@ -59,21 +64,23 @@ module Boty
59
64
  end
60
65
 
61
66
  describe "#match", :users do
62
- let(:data) {{
63
- "type" => "message",
64
- "text" => "bbq omg lol"
65
- }}
67
+ let(:data) do
68
+ {
69
+ "type" => "message",
70
+ "text" => "bbq omg lol"
71
+ }
72
+ end
66
73
 
67
74
  it "binds a regex to events of `type => message`" do
68
- _message = nil
75
+ message = nil
69
76
  bot.match(/omg/i) do
70
- _message = message
77
+ message = self.message
71
78
  end
72
79
  bot.event data
73
80
 
74
- expect(_message).to be_a Boty::Slack::Message
75
- expect(_message.text).to eq "bbq omg lol"
76
- expect(_message.match[0]).to eq "omg"
81
+ expect(message).to be_a Boty::Slack::Message
82
+ expect(message.text).to eq "bbq omg lol"
83
+ expect(message.match[0]).to eq "omg"
77
84
  end
78
85
 
79
86
  it "binds various actions to events of type message" do
@@ -82,23 +89,22 @@ module Boty
82
89
  bot.match(/omg/i) do iterations << "second" end
83
90
  bot.event data
84
91
 
85
- expect(iterations).to eq ["first", "second"]
92
+ expect(iterations).to eq %w(first second)
86
93
  end
87
94
 
88
95
  it "passes the matched strings as parameters to block action" do
89
- _lol, _bbq = nil
96
+ rspec = self
90
97
  bot.match(/(bbq) omg (lol)/i) do |bbq, lol|
91
- _lol, _bbq = lol, bbq
98
+ rspec.expect(bbq).to rspec.eq "bbq"
99
+ rspec.expect(lol).to rspec.eq "lol"
92
100
  end
93
- bot.event data
94
101
 
95
- expect(_lol).to eq "lol"
96
- expect(_bbq).to eq "bbq"
102
+ bot.event data
97
103
  end
98
104
 
99
105
  it "evals the block in the context of the bot" do
100
106
  dsl = nil
101
- bot.match(/omg/) { dsl = self }
107
+ bot.match(/omg/) do dsl = self end
102
108
  bot.event data
103
109
 
104
110
  expect(dsl.bot).to eq bot
@@ -106,10 +112,12 @@ module Boty
106
112
  end
107
113
 
108
114
  describe "#respond", :users do
109
- let(:data) {{
110
- "type" => "message",
111
- "text" => "hey <@jabber>, omg me"
112
- }}
115
+ let(:data) do
116
+ {
117
+ "type" => "message",
118
+ "text" => "hey <@jabber>, omg me"
119
+ }
120
+ end
113
121
 
114
122
  it "binds actions for messages only when there is a mention (@bot)" do
115
123
  expect { |b|
@@ -146,7 +154,7 @@ module Boty
146
154
 
147
155
  it "evals the block in the context of the bot" do
148
156
  dsl = nil
149
- bot.respond(/omg me/) { dsl = self }
157
+ bot.respond(/omg me/) do dsl = self end
150
158
  bot.event data
151
159
 
152
160
  expect(dsl.bot).to eq bot
@@ -159,10 +167,12 @@ module Boty
159
167
  end
160
168
 
161
169
  describe "#no_match" do
162
- let(:data) {{
163
- "type" => "message",
164
- "text" => "bbq omg lol"
165
- }}
170
+ let(:data) do
171
+ {
172
+ "type" => "message",
173
+ "text" => "bbq omg lol"
174
+ }
175
+ end
166
176
 
167
177
  it "removes a message based on the regex AND the block" do
168
178
  permanent_executed = false
@@ -182,8 +192,8 @@ module Boty
182
192
 
183
193
  it "removes all binds for a specific regex" do
184
194
  first = second = false
185
- bot.match(/omg/i) { first = true }
186
- bot.match(/omg/i) { second = true }
195
+ bot.match(/omg/i) do first = true end
196
+ bot.match(/omg/i) do second = true end
187
197
  bot.no_match(/omg/i)
188
198
 
189
199
  bot.event data
@@ -194,10 +204,12 @@ module Boty
194
204
  end
195
205
 
196
206
  describe "#no_respond" do
197
- let(:data) {{
198
- "type" => "message",
199
- "text" => "hey <@#{bot.name}>, omg me"
200
- }}
207
+ let(:data) do
208
+ {
209
+ "type" => "message",
210
+ "text" => "hey <@#{bot.name}>, omg me"
211
+ }
212
+ end
201
213
 
202
214
  it "removes a message based on the regex AND the block" do
203
215
  permanent_executed = false
@@ -217,8 +229,8 @@ module Boty
217
229
 
218
230
  it "removes all binds for a specific regex" do
219
231
  first = second = false
220
- bot.respond(/omg/i) { first = true }
221
- bot.respond(/omg/i) { second = true }
232
+ bot.respond(/omg/i) do first = true end
233
+ bot.respond(/omg/i) do second = true end
222
234
  bot.no_respond(/omg/i)
223
235
 
224
236
  dsl.bot.event data
@@ -231,22 +243,22 @@ module Boty
231
243
 
232
244
  describe "#say" do
233
245
  it "sends a string using the slack api to general (default) channel" do
234
- expect(Slack.chat).to receive(:post_message).
235
- with "something", channel: "#general"
246
+ expect(Slack.chat).to receive(:post_message)
247
+ .with "something", channel: "#general"
236
248
 
237
249
  bot.say "something"
238
250
  end
239
251
 
240
252
  it "sends a message to the channel specified by parameter" do
241
- expect(Slack.chat).to receive(:post_message).
242
- with "omg pugs!", channel: "#omg"
253
+ expect(Slack.chat).to receive(:post_message)
254
+ .with "omg pugs!", channel: "#omg"
243
255
 
244
256
  bot.say "omg pugs!", channel: "#omg"
245
257
  end
246
258
 
247
259
  it "accepts extra parameters and send them to the slack api" do
248
- expect(Slack.chat).to receive(:post_message).
249
- with "omg pugs!", channel: "#omg", omg: "lol"
260
+ expect(Slack.chat).to receive(:post_message)
261
+ .with "omg pugs!", channel: "#omg", omg: "lol"
250
262
 
251
263
  bot.say "omg pugs!", channel: "#omg", omg: "lol"
252
264
  end
@@ -262,9 +274,9 @@ module Boty
262
274
 
263
275
  describe "#im" do
264
276
  before do
265
- allow(Slack.users).to receive(:by_name).
266
- with("julian").
267
- and_return(Boty::Slack::User.new "id" => "U123", "name" => "julian")
277
+ user = Boty::Slack::User.new "id" => "U123", "name" => "julian"
278
+ allow(Slack.users).to receive(:by_name).with("julian")
279
+ .and_return user
268
280
  end
269
281
 
270
282
  it "sends a message in the back channel (particular, im...)" do
@@ -287,9 +299,8 @@ module Boty
287
299
  end
288
300
 
289
301
  it "logs when fails on discover the destiny", :logger do
290
- allow(Slack.users).to receive(:by_name).
291
- with("omg_doesnt_exists").
292
- and_return nil
302
+ allow(Slack.users).to receive(:by_name)
303
+ .with("omg_doesnt_exists").and_return nil
293
304
  bot.im "lol", destiny: "omg_doesnt_exists"
294
305
 
295
306
  expect(logger.logs.last).to eq "User not found, refusing to send im."
@@ -304,46 +315,52 @@ module Boty
304
315
  end
305
316
 
306
317
  describe "#desc" do
318
+ let(:know_how) {
319
+ bot.know_how.map { |action|
320
+ { action.desc.command => action.desc.description }
321
+ }
322
+ }
323
+
307
324
  it "describes the next command to be created" do
308
325
  bot.desc "omg", "lol all the way down"
309
- bot.respond(/omg/) {}
326
+ bot.respond(/omg/)
310
327
 
311
- expect(bot.know_how).to include({
328
+ expect(know_how).to include(
312
329
  "omg" => "lol all the way down"
313
- })
330
+ )
314
331
  end
315
332
 
316
333
  it "describes the next match do be created" do
317
334
  bot.desc "ula", "babula"
318
- bot.match(/ula/) {}
335
+ bot.match(/ula/)
319
336
 
320
- expect(bot.know_how).to include({
337
+ expect(know_how).to include(
321
338
  "ula" => "babula"
322
- })
339
+ )
323
340
  end
324
341
 
325
342
  it "stores the description for a regex when no command usage is given" do
326
343
  bot.desc "just a description"
327
- bot.match(/just desc/i) {}
328
- expect(bot.know_how).to include({
344
+ bot.match(/just desc/i)
345
+ expect(know_how).to include(
329
346
  "/just desc/i" => "just a description"
330
- })
347
+ )
331
348
  end
332
349
 
333
350
  it "presents the commands without description as regexes" do
334
- bot.match(/without desc/i) {}
351
+ bot.match(/without desc/i)
335
352
 
336
- expect(bot.know_how).to include({
353
+ expect(know_how).to include(
337
354
  "/without desc/i" => nil
338
- })
355
+ )
339
356
  end
340
357
 
341
358
  it "knows when a regex is case insensitive" do
342
359
  bot.match(/without desc insensitive/)
343
360
 
344
- expect(bot.know_how).to include({
361
+ expect(know_how).to include(
345
362
  "/without desc insensitive/" => nil
346
- })
363
+ )
347
364
  end
348
365
  end
349
366
  end