boty 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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