slack-ruby-bot-boilerplate 0.1.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.
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'bundler/gem_tasks'
4
+
5
+ Bundler.setup :default, :development
6
+
7
+ unless ENV['RACK_ENV'] == 'production'
8
+ require 'rspec/core'
9
+ require 'rspec/core/rake_task'
10
+
11
+ RSpec::Core::RakeTask.new(:spec) do |spec|
12
+ spec.pattern = FileList['spec/**/*_spec.rb']
13
+ end
14
+
15
+ require 'rubocop/rake_task'
16
+ RuboCop::RakeTask.new
17
+
18
+ task default: %i[rubocop spec]
19
+ end
@@ -0,0 +1,218 @@
1
+ ## Production Bot Tutorial
2
+
3
+ In this tutorial we'll implement [slack-mathbot](https://github.com/dblock/slack-mathbot).
4
+
5
+ ### Introduction
6
+
7
+ A typical production Slack bot is a combination of a vanilla web server and a websocket application that talks to the [Slack Real Time Messaging API](https://api.slack.com/rtm). The web server is optional, but most people will run their Slack bots on [Heroku](https://dashboard.heroku.com) in which case a web server is required to prevent Heroku from shutting the bot down. It also makes it convenient to develop a bot and test using `foreman`.
8
+
9
+ ### Getting Started
10
+
11
+ #### Gemfile
12
+
13
+ Create a `Gemfile` that uses [slack-ruby-bot](https://github.com/slack-ruby/slack-ruby-bot), [sinatra](https://github.com/sinatra/sinatra) (a web framework) and [puma](https://github.com/puma/puma) (a web server). For development we'll also use [foreman](https://github.com/theforeman/foreman) and write tests with [rspec](https://github.com/rspec/rspec).
14
+
15
+ ```ruby
16
+ source 'https://rubygems.org'
17
+
18
+ gem 'slack-ruby-bot'
19
+ gem 'puma'
20
+ gem 'sinatra'
21
+ gem 'dotenv'
22
+ gem 'celluloid-io'
23
+
24
+ group :development, :test do
25
+ gem 'rake'
26
+ gem 'foreman'
27
+ end
28
+
29
+ group :test do
30
+ gem 'rspec'
31
+ gem 'rack-test'
32
+ gem 'vcr'
33
+ gem 'webmock'
34
+ end
35
+ ```
36
+
37
+ Run `bundle install` to get all the gems.
38
+
39
+ #### Application
40
+
41
+ Create a folder called `slack-mathbot` and inside of it create `bot.rb`.
42
+
43
+ ```ruby
44
+ module SlackMathbot
45
+ class Bot < SlackRubyBot::Bot
46
+ end
47
+ end
48
+ ```
49
+
50
+ #### Commands
51
+
52
+ Create a folder called `slack-mathbot/commands` and inside of it create `calculate.rb`. For now this calculator will always return 4.
53
+
54
+ ```ruby
55
+ module SlackMathbot
56
+ module Commands
57
+ class Calculate < SlackRubyBot::Commands::Base
58
+ command 'calculate' do |client, data, _match|
59
+ client.say(channel: data.channel, text: '4')
60
+ end
61
+ end
62
+ end
63
+ end
64
+ ```
65
+
66
+ #### Require Everything
67
+
68
+ Create a `slack-mathbot.rb` at the root and require the above files.
69
+
70
+ ```ruby
71
+ require 'slack-ruby-bot'
72
+ require 'slack-mathbot/commands/calculate'
73
+ require 'slack-mathbot/bot'
74
+ ```
75
+
76
+ #### Web Server
77
+
78
+ We will need to keep the bot alive on Heroku, so create `web.rb`.
79
+
80
+ ```ruby
81
+ require 'sinatra/base'
82
+
83
+ module SlackMathbot
84
+ class Web < Sinatra::Base
85
+ get '/' do
86
+ 'Math is good for you.'
87
+ end
88
+ end
89
+ end
90
+ ```
91
+
92
+ #### Config.ru
93
+
94
+ Tie all the pieces together in `config.ru` which creates a thread for the bot and runs the web server on the main thread.
95
+
96
+ ```ruby
97
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
98
+
99
+ require 'dotenv'
100
+ Dotenv.load
101
+
102
+ require 'slack-mathbot'
103
+ require 'web'
104
+
105
+ Thread.abort_on_exception = true
106
+
107
+ Thread.new do
108
+ begin
109
+ SlackMathbot::Bot.run
110
+ rescue Exception => e
111
+ STDERR.puts "ERROR: #{e}"
112
+ STDERR.puts e.backtrace
113
+ raise e
114
+ end
115
+ end
116
+
117
+ run SlackMathbot::Web
118
+ ```
119
+
120
+ ### Create a Bot User
121
+
122
+ In Slack administration create a new Bot Integration under [services/new/bot](http://slack.com/services/new/bot).
123
+
124
+ ![](screenshots/register-bot.png)
125
+
126
+ On the next screen, note the API token.
127
+
128
+ #### .env
129
+
130
+ Create a `.env` file with the API token from above and make sure to add it to `.gitignore`.
131
+
132
+ ```
133
+ SLACK_API_TOKEN=...
134
+ ```
135
+
136
+ ### Procfile
137
+
138
+ Create a `Procfile` which `foreman` will use when you run the `foreman start` command below.
139
+
140
+ ```
141
+ web: bundle exec puma -p $PORT
142
+ ```
143
+
144
+ ### Run the Bot
145
+
146
+ Run `foreman start`. Your bot should be running.
147
+
148
+ ```
149
+ 14:32:32 web.1 | Puma starting in single mode...
150
+ 14:32:32 web.1 | * Version 2.11.3 (ruby 2.1.6-p336), codename: Intrepid Squirrel
151
+ 14:32:32 web.1 | * Min threads: 0, max threads: 16
152
+ 14:32:32 web.1 | * Environment: development
153
+ 14:32:35 web.1 | * Listening on tcp://0.0.0.0:5000
154
+ 14:32:35 web.1 | Use Ctrl-C to stop
155
+ 14:32:36 web.1 | I, [2015-07-10T14:32:36.216663 #98948] INFO -- : Welcome 'mathbot' to the 'xyz' team at https://xyz.slack.com/.
156
+ 14:32:36 web.1 | I, [2015-07-10T14:32:36.766955 #98948] INFO -- : Successfully connected to https://xyz.slack.com/.
157
+ ```
158
+
159
+ ### Try
160
+
161
+ Invite the bot to a channel via `/invite [bot name]` and send it a `calculate` command with `[bot name] calculate 2+2`. It will respond with `4` from the code above.
162
+
163
+ ### Write Tests
164
+
165
+ #### Spec Helper
166
+
167
+ Create `spec/spec_helper.rb` that includes the bot files and shared RSpec support from slack-ruby-bot.
168
+
169
+ ```ruby
170
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
171
+
172
+ require 'slack-ruby-bot/rspec'
173
+ require 'slack-mathbot'
174
+ ```
175
+
176
+ #### Test the Bot Application
177
+
178
+ Create a test for the bot application itself in `spec/slack-mathbot/bot_spec.rb`.
179
+
180
+ ```ruby
181
+ require 'spec_helper'
182
+
183
+ describe SlackMathbot::Bot do
184
+ def app
185
+ SlackMathbot::Bot.instance
186
+ end
187
+
188
+ subject { app }
189
+
190
+ it_behaves_like 'a slack ruby bot'
191
+ end
192
+ ```
193
+
194
+ #### Test a Command
195
+
196
+ Create a test for the `calculate` command in `spec/slack-mathbot/commands/calculate_spec.rb`. The bot is addressed by its user name.
197
+
198
+ ```ruby
199
+ require 'spec_helper'
200
+
201
+ describe SlackMathbot::Commands::Calculate do
202
+ def app
203
+ SlackMathbot::Bot.instance
204
+ end
205
+
206
+ subject { app }
207
+
208
+ it 'returns 4' do
209
+ expect(message: "#{SlackRubyBot.config.user} calculate 2+2", channel: 'channel').to respond_with_slack_message('4')
210
+ end
211
+ end
212
+ ```
213
+
214
+ See [lib/slack-ruby-bot/rspec/support/slack-ruby-bot](lib/slack-ruby-bot/rspec/support/slack-ruby-bot) for other shared RSpec behaviors.
215
+
216
+ ### Deploy
217
+
218
+ See [DEPLOYMENT](DEPLOYMENT.md) for how to deploy your bot to production.
@@ -0,0 +1,226 @@
1
+ Upgrading SlackRubyBot
2
+ ======================
3
+
4
+ ### Upgrading to >= 0.12.0
5
+
6
+ #### Remove any references to `SlackRubyBot::Server#restart!`
7
+
8
+ We have removed `SlackRubyBot::Server#restart!` since the [`slack-ruby-client`](https://github.com/slack-ruby/slack-ruby-client/blob/master/CHANGELOG.md) now restarts any connection that was not intentionally stopped via `SlackRubyBot::Server#stop!`.
9
+
10
+ ### Upgrading to >= 0.10.4
11
+
12
+ #### Replace `server.hooks.add` with `server.on`
13
+
14
+ We have deprecated `SlackRubyBot::Server#hooks` in favor of `SlackRubyBot::Server#on` instance method. All users using `SlackRubyBot::Server#hooks` method should
15
+ change their codebase and use the new method instead. Method signature is not affected.
16
+
17
+ Example:
18
+
19
+ ```ruby
20
+ # Given server is an instance of SlackRubyBot::Server
21
+ #
22
+ # Before
23
+ server.hooks.add :hello, Greet.new
24
+
25
+ # After
26
+ server.on :hello, Greet.new
27
+ ```
28
+
29
+ ### Upgrading to >= 0.9.0
30
+
31
+ #### Add giphy to your Gemfile for GIF support
32
+
33
+ The dependency on the `giphy` gem was dropped and GIFs don't appear by default. If you want GIF support, add `gem 'giphy'` to your **Gemfile**.
34
+
35
+ You should not need to make any changes if you had already disabled GIFs for your bot.
36
+
37
+ See [#89](https://github.com/slack-ruby/slack-ruby-bot/pull/89) for more information.
38
+
39
+ ### Upgrading to >= 0.8.0
40
+
41
+ #### Require a concurrency library
42
+
43
+ The `faye-websocket` library is no longer required by default. Add either `faye-websocket` or `celluiloid-io` to your `Gemfile` depending on which concurrency implementation you'd like to use. We recommend `celluloid-io` moving forward.
44
+
45
+ #### Hook::Base was removed, explicitly register any custom hook classes
46
+
47
+ Hook classes are now handled differently, namely they are explicitly registered into `SlackRubyBot::Server` via a configuration option (`hook_handlers`) or by passing a similar hash later on through the `add_hook_handlers` method. Including Hook classes directly into the server class is no longer needed.
48
+
49
+ A hook is actioned via a `call` message onto the handler object (this can be anything that responds to that), so you'll need to rename your method.
50
+
51
+ Finally, you can now register multiple hooks for the same event, so if you had any code to remove default hooks, you'll need to change it so you pass a configuration hash into `Server`
52
+
53
+ ### Upgrading to >= 0.7.0
54
+
55
+ #### Simplify Match Expression Checking
56
+
57
+ The regular expression parser for commands will now include a `nil` value for `expression` when an expression is not present. You can therefore no longer rely on checking `match.names.include?('expression')`, instead check `match['expression']`.
58
+
59
+ #### Remove any bot.auth! calls
60
+
61
+ SlackRubyBot 0.6.x versions invoked a method called `auth!`, which caused a pre-flight authentication via Slack Web API `auth_test` method and collected a number of properties, such as client and team ID or name. This method has been removed in favor of using data available in the `Slack::RealTime::Client` local store introduced in [slack-ruby-client#54](https://github.com/slack-ruby/slack-ruby-client/issues/54). Remove any explicit calls to this method.
62
+
63
+ ### Upgrading to >= 0.6.0
64
+
65
+ While entirely compatible with the 0.5.x series, a number of methods have been deprecated and will be removed in the next release.
66
+
67
+ #### Replace SlackRubyBot::Commands::Base#call with command, operator or match
68
+
69
+ Prefer `command`, `operator` or `match` with a block instead of implementing a `self.call` method.
70
+
71
+ Before:
72
+
73
+ ```ruby
74
+ require 'slack-ruby-bot'
75
+
76
+ class Bot < SlackRubyBot::Bot
77
+ command 'ping'
78
+
79
+ def self.call(client, data, match)
80
+ ...
81
+ end
82
+ end
83
+ ```
84
+
85
+ After:
86
+
87
+ ```ruby
88
+ require 'slack-ruby-bot'
89
+
90
+ class Bot < SlackRubyBot::Bot
91
+ command 'ping' do |client, data, match|
92
+ ...
93
+ end
94
+ end
95
+ ```
96
+
97
+ #### Replace send_message, send_message_with_gif and send_gif with client.say
98
+
99
+ Use `client.say` instead of `send_message`, `send_message_with_gif` and `send_gif` in commands.
100
+
101
+ Before:
102
+
103
+ ```ruby
104
+ class Bot < SlackRubyBot::Bot
105
+ command 'one' do |client, data, match|
106
+ send_message client, data.channel, 'Text.'
107
+ end
108
+
109
+ command 'two' do |client, data, match|
110
+ send_message_with_gif client, data.channel, "Text.", 'keyword'
111
+ end
112
+
113
+ command 'three' do |client, data, match|
114
+ send_gif client, data.channel, 'keyword'
115
+ end
116
+ end
117
+ ```
118
+
119
+ After:
120
+
121
+ ```ruby
122
+ class Bot < SlackRubyBot::Bot
123
+ command 'one' do |client, data, match|
124
+ client.say(channel: data.channel, text: 'Text.')
125
+ end
126
+
127
+ command 'two' do |client, data, match|
128
+ client.say(channel: data.channel, text: 'Text.', gif: 'keyword')
129
+ end
130
+
131
+ command 'three' do |client, data, match|
132
+ client.say(channel: data.channel, gif: 'keyword')
133
+ end
134
+ end
135
+ ```
136
+
137
+ #### For basic bots replace SlackRubyBot::App with SlackRubyBot::Bot and implement commands inline
138
+
139
+ Before:
140
+
141
+ ```ruby
142
+ module PongBot
143
+ class App < SlackRubyBot::App
144
+ end
145
+
146
+ class Ping < SlackRubyBot::Commands::Base
147
+ command 'ping' do |client, data, _match|
148
+ client.message(text: 'pong', channel: data.channel)
149
+ end
150
+ end
151
+ end
152
+
153
+ PongBot::App.instance.run
154
+ ```
155
+
156
+ After:
157
+
158
+ ```ruby
159
+ class Bot < SlackRubyBot::Bot
160
+ command 'ping' do |client, data, _match|
161
+ client.say(text: 'pong', channel: data.channel)
162
+ end
163
+ end
164
+
165
+ Bot.run
166
+ ```
167
+
168
+ ### Upgrading to >= 0.4.0
169
+
170
+ This version uses [slack-ruby-client](https://github.com/slack-ruby/slack-ruby-client) instead of [slack-ruby-gem](https://github.com/aki017/slack-ruby-gem).
171
+
172
+ The command interface now takes a `client` parameter, which is the RealTime Messaging API instance. Add the new parameter to all `call` calls in classes that inherit from `SlackRubyBot::Commands::Base`.
173
+
174
+ Before:
175
+
176
+ ```ruby
177
+ def self.call(data, match)
178
+ ...
179
+ end
180
+ ```
181
+
182
+ After:
183
+
184
+ ```ruby
185
+ def self.call(client, data, match)
186
+ ...
187
+ end
188
+ ```
189
+
190
+ This also applies to `command`, `operator` and `match` blocks.
191
+
192
+ Before:
193
+
194
+ ```ruby
195
+ command 'ping' do |data, match|
196
+ ...
197
+ end
198
+ ```
199
+
200
+ After:
201
+
202
+ ```ruby
203
+ command 'ping' do |client, data, match|
204
+ ...
205
+ end
206
+ ```
207
+
208
+ You can now send messages directly via the RealTime Messaging API.
209
+
210
+ ```ruby
211
+ client.message text: 'text', channel: 'channel'
212
+ ```
213
+
214
+ Otherwise you must now pass the `client` parameter to `send_message` and `send_message_with_gif`.
215
+
216
+ ```ruby
217
+ def self.call(client, data, match)
218
+ send_message client, data.channel, 'hello'
219
+ end
220
+ ```
221
+
222
+ ```ruby
223
+ def self.call(client, data, match)
224
+ send_message_with_gif client, data.channel, 'hello', 'hi'
225
+ end
226
+ ```