The easiest way to write a Slack bot in Ruby.
The easiest way to write a Slack bot in Ruby.
Warning: As of December 4th, 2020 Slack no longer accept resubmissions from apps that are not using granular permissions, or so-called "classic apps". On November 18, 2021 Slack will start delisting apps that have not migrated to use granular permissions. This library implements legacy, real-time support for classic apps. You should not be building a new bot with it and use slack-ruby-bot-server-events instead. For a rudimentary bot you can even start with slack-ruby-bot-server-events-app-mentions. See MIGRATION for migration help.
The slack-ruby-bot library is a generic Slack bot framework written in Ruby on top of slack-ruby-client. This library does all the heavy lifting, such as message parsing, so you can focus on implementing slack bot commands. It also attempts to introduce the bare minimum number of requirements or any sorts of limitations. It's a Slack bot boilerplate.
If you are not familiar with Slack bots or Slack API concepts, you might want to watch this video.
You're reading the documentation for the next release of slack-ruby-bot. Please see the documentation for the last stable release, v0.16.1 unless you're integrating with HEAD. See CHANGELOG for a history of changes and UPGRADING for how to upgrade to more recent versions.
source 'https://rubygems.org'
gem 'slack-ruby-bot'
gem 'async-websocket', '~>0.8.0'…SLACK_RUBY_BOT_ALIASES=:pp: table-tennis
```ruby
SlackRubyBot.configure do |config|
config.aliases = [':pong:', 'pongbot']
endBots will also respond to a direct message, with or without the bot name in the message itself.
Commands and operators are generic versions of bot routes. You can respond to just about anything by defining a custom route.
class Weather \w*)\?$/ do |client, data, match|
client.say(channel: data.channel, text: "The weather in #{match[:location]} is nice.")
end
endYou can also capture multiple matchers with scan.
class Market ?' do
desc 'Tells you the weather in a .'
long_desc "Accurate 10 Day Weather Forecasts for thousands of places around the World.\n" \
'Bot provides detailed Weather Forecasts over a 10 day period updated four times a day.'
end
end
# commands implementation
endin case of your own command:
class Deploy * where is production or staging'
end
endIf you've used the help block described above to document your
commands, you can provide your own implementation of outputting help
for commands like so:
class Market (client, data) { }, ->(client, data) {}]
})SlackRubyBot::Server instance# Register an object that implements `call` method
class MyBot::Hooks::Hello
def call(client, data)
puts "Hello"
end
end
server.on(:hello, MyBot::Hooks::Hello.new)
# or register a lambda function to handle the event
server.on(:hello, ->(client, data) { puts "Hello!" })For example, the following hook handles user_change, an event sent when a team member updates their profile or data. This can be useful to update the local user cache when a user is renamed.
module MyBot
module Hooks
class UserChange
def call(client, data)
# data['user']['id'] contains the user ID
# data['user']['name'] contains the new user name
# ...
end
end
end
endSlackRubyBot::Server classExample:
module MyBot
class MyServer (client, data) {
# data['user']['id'] contains the user ID
# data['user']['name'] contains the new user name
}
end
endThese will get pushed into the hook set on initialization.
Either by configuration, explicit assignment or hook blocks, multiple handlers can exist for the same event type.
By default bots do not respond to self or other bots. If you wish to change that behavior globally, set allow_bot_messages to true.
SlackRubyBot.configure do |config|
config.allow_bot_messages = true
endBy default bots do not respond to their own messages. If you wish to change that behavior globally, set allow_message_loops to true.
SlackRubyBot.configure do |config|
config.allow_message_loops = true
endBy default bots set a logger to $stdout with DEBUG level. The logger is used in both the RealTime and Web clients.
Silence logger as follows.
SlackRubyBot::Client.logger.level = Logger::WARNIf you wish to customize logger, set logger to your logger.
SlackRubyBot.configure do |config|
config.logger = Logger.new("slack-ruby-bot.log", "daily")
endYou may want to integrate a bot or multiple bots into other systems, in which case a globally configured bot may not work for you. You may create instances of SlackRubyBot::Server which accepts token and aliases.
EM.run do
bot1 = SlackRubyBot::Server.new(token: token1, aliases: ['bot1'])
bot1.start_async
bot2 = SlackRubyBot::Server.new(token: token2, aliases: ['bot2'])
bot2.start_async
end
…
ruby
class Agent resource)
# ... do some expensive work
end
end
private
def sanitize_resource
self._resource.downcase
result = yield
puts "After read, result is #{result.inspect}"
end
end
…
ruby
class MyView < SlackRubyBot::MVC::View::Base
define_callbacks :logit
set_callbacks :logit, :around, :audit_trail
def initialize
@mailer = setup_mailer
@ftp = setup_ftp_handler
end
def email_admin(message)
run_callbacks :logit do
@mailer.send(:administrator, message)
end
end
def react_thumbsup
client.web_client.reactions_add(
name: :thumbsup,
channel: data.channel,
timestamp: data.ts,
as_user: true)
end
def react_thumbsdown
client.web_client.reactions_remove(
name: :thumbsup,
channel: data.channel,
timestamp: data.ts,
as_user: true)
end
private
def audit_trail
Logger.audit("Sending email at [#{Time.now}]")
yield
Logger.audit("Email sent by [#{Time.now}]")
end
end
…
ruby
group :development, :test do
gem 'rack-test'
gem 'rspec'
gem 'vcr'
gem 'webmock'
endUse the respond_with_slack_message matcher.
describe SlackRubyBot::Commands do
it 'responds with any message' do
expect(message: "#{SlackRubyBot.config.user} hi").to respond_with_slack_message
end
it 'says hi' do
expect(message: "#{SlackRubyBot.config.user} hi").to respond_with_slack_message('hi')
end
endUse the respond_with_slack_messages matcher for multiple messages.
describe SlackRubyBot::Commands do
it 'responds with more than one message' do
expect(message: "#{SlackRubyBot.config.user} count").to respond_with_slack_messages
end
it 'says one and two' do
expect(message: "#{SlackRubyBot.config.user} count").to respond_with_slack_messages(['one', 'two'])
end
endMessage matchers support regular expressions.
describe SlackRubyBot::Commands do
it 'says hi' do
expect(message: "#{SlackRubyBot.config.user} hi").to respond_with_slack_message(/hi/)
end
endCheck that the bot called client.start_typing(channel: 'channel').
describe SlackRubyBot::Commands do
it 'starts typing on channel' do
expect(message: "#{SlackRubyBot.config.user} hi").to start_typing(channel: 'channel')
end
endYou can test client behavior at a lower level by fetching the message hook. The following example expects a bot command to call client.typing(channel: data.channel).
describe SlackRubyBot::Commands do
let(:app) { Server.new }
let(:client) { app.send(:client) }
let(:message_hook) { SlackRubyBot::Hooks::Message.new }
it 'receives a typing event' do
expect(client).to receive(:typing)
message_hook.call(
client,
Hashie::Mash.new(text: "#{SlackRubyBot.config.user} type something", channel: 'channel')
)
end
end
endSee CONTRIBUTING.
See CHANGELOG for a history of changes and UPGRADING for how to upgrade to more recent versions.
Copyright (c) 2015-2020, Daniel Doubrovkine, Artsy and Contributors.
This project is licensed under the MIT License.
No open issues yet, or sync has not completed.