slack_message 2.3.0 → 3.0.1

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
  SHA256:
3
- metadata.gz: 4b476b987543e7a38fd316de55186ddee859dfc1bd71817b14ddd13b2cb79f59
4
- data.tar.gz: 80932a2d8e1bcac51239ea7724cd42f419dadfb7061fd939f359c2f4a5743777
3
+ metadata.gz: '098b332b278741ef63ef105fc7e79cbc7ef131a03dca79b0ed40a1d86001cae1'
4
+ data.tar.gz: 40a4028d38c154fdb1d1835e0f536adc2e57671223290e43a139be1d70a359c3
5
5
  SHA512:
6
- metadata.gz: c6273ff440e4aa2fd9c4dba40c7e45e4c3840d02d7619dafb11d516f9a3541172499e0e81f1966103a89332bb3911fb96818984fadc0195faa27c9b5e1692fcb
7
- data.tar.gz: fc1a7df622d0cfd0c10311a70478cba43b893d7cde189d4f55dd997196e544145f8ce855a4b82af920f4320314907a6fe91bb39fddf3ba5e9460d4b8a4cbb33a
6
+ metadata.gz: f99700c2fcb33cc7ad9e671f250dc23efffd47e6f4e36d9fdc7740c9ed1a8d4b224b523b6870b13cb3b164a0ae720f93824fae803368083919d776ec2c221236
7
+ data.tar.gz: 1fb9ccc9bf2f9b9fabca5e1cdcdbcde87100f1c056613f0af1450f344bc82adcc5f7366d2f6ab8fb54e34f241018464283c750f2a0d022a67112b9570fc1287e
@@ -11,7 +11,7 @@ jobs:
11
11
  strategy:
12
12
  matrix:
13
13
  os: [ubuntu-latest, macos-latest]
14
- ruby-version: [3.0, 2.7, 2.6]
14
+ ruby-version: [3.0, 2.7, 2.6, 2.5]
15
15
  runs-on: ${{ matrix.os }}
16
16
 
17
17
  steps:
data/.gitignore CHANGED
@@ -1 +1,2 @@
1
+ Gemfile.lock
1
2
  slack_message*.gem
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.0.1] - 2021-12-22
4
+ - Major overhaul of error handling and expansion on which errors trigger
5
+ friendly messages for users.
6
+ - More additions to the docs, and working github pages integration.
7
+ - It's my birthday!
8
+
9
+ ## [3.0.0] - 2021-12-19
10
+ - Return a more structured object from successful message sends.
11
+ - Add the ability to edit or delete a message.
12
+ - Complete overhaul of docs because they were too large.
13
+
14
+ ## [2.4.0] - 2021-12-13
15
+ - Add ability to schedule messages, plus some guard rails around that.
16
+ - Add ability to debug by logging out the total set of params sent to the API.
17
+
18
+ ## [2.3.1] - 2021-11-30
19
+ - Adjust that minimum version by changing some syntax to older styles. Given
20
+ support for ruby 2.4 ended almost 2 years ago, going to go ahead and leave
21
+ it behind.
22
+ - Remove lockfile from repo
23
+
3
24
  ## [2.3.0] - 2021-11-30
4
25
  - Formally require minimum version of ruby. It wouldn't have worked anyway,
5
26
  but worth actually specifying.
data/README.md CHANGED
@@ -12,173 +12,14 @@ SlackMessage.post_to('#general') do
12
12
  text "We did it @here! :thumbsup:"
13
13
  end
14
14
  ```
15
+
16
+ ### The Docs
15
17
 
16
- To install, just add `slack_message` to your bundle and you're ready to go.
17
-
18
- #### Opinionated Stances
19
-
20
- Slack's API has a lot of options available to you! But this gem takes some
21
- opinionated stances about usage to try to minimize the pain of integrating
22
- with it. For example:
23
-
24
- * SlackMessage has no dependencies. Your lockfile is enough of a mess already.
25
- * The code to build a message should look a lot like the message itself. Code
26
- that is simple to read and understand is a priority.
27
- * Webhooks are passé. Only Slack Apps are supported now.
28
- * Unless you request otherwise, text is always rendered using `mrkdwn`. If you
29
- want plaintext, you'll need to ask for it. Same for the `emoji` flag.
30
- * As many API semantics as possible are hidden. For instance, if you post to
31
- something that looks like an email address, `slack_message` is going to try
32
- to look it up as an email address.
33
- * A few little hacks on the block syntax, such as adding a `blank_line` (which
34
- doesn't exist in the API), or leading spaces.
35
- * Configuration is kept as simple as possible. But, as much heavy lifting as
36
- possible should occur just once via configuration and not on every call.
37
-
38
- Usage
39
- ------------
40
-
41
- ### Configuration
42
-
43
- To get started, you'll need to create a Slack App with some appropriate
44
- permissions. It used to be possible to use the Webhook API, but that's long
45
- since been deprecated, and apps are pretty [straightforward to
46
- create](https://api.slack.com/tutorials/tracks/getting-a-token).
47
-
48
- Generally, make sure your token has permissions for `users:read` and `chat:write`.
49
-
50
- ```ruby
51
- SlackMessage.configure do |config|
52
- api_token = 'xoxb-11111111111-2222222222-33333333333333333'
53
-
54
- config.add_profile(api_token: api_token)
55
- end
56
- ```
57
-
58
- You should keep your token in a safe place like `ENV`. If using this gem with
59
- Rails, place this code in somewhere like `config/initializers/slack_message.rb`.
60
-
61
- #### Additional Profiles
62
-
63
- If your app uses slack messages for several different purposes, it's common to
64
- want to post to different channels as different names / icons / etc. To do that
65
- more easily and consistently, you can specify multiple profiles:
66
-
67
- ```ruby
68
- SlackMessage.configure do |config|
69
- api_token = 'xoxb-11111111111-2222222222-33333333333333333'
70
-
71
- # default profile
72
- config.add_profile(api_token: api_token, name: 'Slack Notifier')
73
-
74
- # additional profiles (see below for usage)
75
- config.add_profile(:prod_alert_bot,
76
- name: 'Prod Alert Bot'
77
- icon: ':mooseandsquirrel:'
78
- )
79
- config.add_profile(:sidekiq_bot,
80
- api_token: ENV.fetch('SIDEKIQ_SLACK_APP_API_TOKEN'),
81
- name: 'Sidekiq Bot',
82
- )
83
- end
84
- ```
85
-
86
- A number of parameters are available to make it simpler to use a profile without
87
- specifying repetitive information. Most all have corresponding options when
88
- composing a message:
89
-
90
- | Config | Default | Value |
91
- |-----------------|-----------------|-----------------------------------------------------------------|
92
- | api_token | None | Your Slack App API Key. |
93
- | name | From Slack App | The bot name for your message. |
94
- | icon | From Slack App | Profile icon for your message. Specify as :emoji: or image URL. |
95
- | default_channel | None (optional) | Channel / user to post to by default. |
96
-
97
-
98
- Setting a `default_channel` specifically will allow you to use `post_as`, which
99
- is a convenient shortcut for bots that repeatedly post to one channel as a
100
- consistent identity:
101
-
102
- ```ruby
103
- SlackMessage.configure do |config|
104
- config.add_profile(:red_alert_bot,
105
- api_token: ENV.fetch('SLACK_API_TOKEN'),
106
- name: 'Red Alerts',
107
- icon: ':klaxon:',
108
- default_channel: '#red_alerts'
109
- )
110
- end
111
-
112
- SlackMessage.post_as(:red_alert_bot) do
113
- text ":ambulance: weeooo weeooo something went wrong"
114
- end
115
- ```
116
-
117
- There's no reason you can't use the same API key for several profiles. Profiles
118
- are most useful to create consistent name / icon setups for apps with many bots.
119
-
120
- ### Posting Messages
121
-
122
- As mentioned at the top, posting a message to Slack is dang easy:
123
-
124
- ```ruby
125
- SlackMessage.post_to('#general') do
126
- text "We did it @here! :thumbsup:"
127
- end
128
- ```
129
-
130
- That's it! SlackMessage will automatically serialize for the API like this:
131
-
132
- ```json
133
- [{"type":"section","text":{"type":"mrkdwn","text":"We did it @here! :thumbsup:"}}]
134
- ```
135
-
136
- Details like remembering that Slack made a mystifying decision to force you to
137
- request "mrkdwn", or requiring your text to be wrapped into a section are handled
138
- for you. Building up messages is meant to be as user-friendly as possible:
139
-
140
- ```ruby
141
- SlackMessage.build do
142
- text "haiku are easy"
143
- text "but sometimes they don't make sense"
144
- text "refrigerator"
145
-
146
- context "- unknown author"
147
- end
148
- ```
149
-
150
- SlackMessage will combine your text declarations and add any necessary wrappers
151
- automatically:
152
-
153
- ```json
154
- [
155
- {
156
- "type": "section",
157
- "text": {
158
- "type": "mrkdwn",
159
- "text": "haiku are easy\nbut sometimes they don't make sense\nrefrigerator"
160
- }
161
- },
162
- {
163
- "type": "context",
164
- "elements": [
165
- {
166
- "type": "mrkdwn",
167
- "text": "- unknown author"
168
- }
169
- ]
170
- }
171
- ]
172
- ```
173
-
174
- It's just as easy to send messages directly to users. SlackMessage will look for
175
- targets that are email-addressish, and look them up for you automatically:
18
+ You'll find much more information about how to use SlackMessage by visiting
19
+ [the docs](https://jmmastey.github.io/slack_message).
20
+
176
21
 
177
- ```ruby
178
- SlackMessage.post_to('hello@joemastey.com') do
179
- text "You specifically did it! :thumbsup:"
180
- end
181
- ```
22
+ ### Posting
182
23
 
183
24
  SlackMessage is able to build all kinds of rich messages for you, and has been
184
25
  a real joy to use for the author at least. To understand a bit more about the
@@ -213,159 +54,42 @@ SlackMessage.post_to('#general') do
213
54
  end
214
55
  ```
215
56
 
216
- SlackMessage will compose this into Block Kit syntax and send it on its way!
217
-
218
- If you've defined multiple profiles in configuration, you can specify which to
219
- use for your message by specifying its name:
220
-
221
- ```ruby
222
- SlackMessage.post_to('#general', as: :sidekiq_bot) do
223
- text ":octagonal_sign: A job has failed permanently and needs to be rescued."
224
-
225
- link_button "Sidekiq Dashboard", sidekiq_dashboard_url, style: :danger
226
- end
227
- ```
228
-
229
- You can also override profile bot details when sending a message:
230
-
231
- ```ruby
232
- SlackMessage.post_to('#general') do
233
- bot_name "CoffeeBot"
234
- bot_icon ":coffee:"
235
-
236
- text ":coffee::clock: Time to take a break!"
237
- end
238
- ```
239
-
240
- #### Notifying Users
241
-
242
- There are several supported ways to tag and notify users. Mentioned above, it's
243
- possible to DM a user by email:
244
-
245
- ```ruby
246
- SlackMessage.post_to('hello@joemastey.com') do
247
- text "Hi there!"
248
- end
249
- ```
250
-
251
- You can also mention a user by email within a channel by wrapping their name
252
- in tags:
253
-
254
- ```ruby
255
- SlackMessage.post_to('#general') do
256
- bot_name "CoffeeBot"
257
- bot_icon ":coffee:"
258
-
259
- text ":coffee: It's your turn to make coffee <hello@joemastey.com>."
260
- end
261
- ```
262
-
263
- Emails that are not wrapped in tags will be rendered as normal email addresses.
264
- Additionally, Slack will automatically convert a number of channel names and
265
- tags you're probably already used to:
266
-
267
- ```ruby
268
- SlackMessage.post_to('#general') do
269
- bot_name "CoffeeBot"
270
- bot_icon ":coffee:"
271
-
272
- text "@here There's no coffee left! Let #general know when you fix it."
273
- end
274
- ```
275
-
276
- By default, the desktop notification for a message will be the text of the
277
- message itself. However, you can customize desktop notifications if you prefer:
278
-
279
- ```ruby
280
- SlackMessage.post_to('hello@joemastey.com') do
281
- bot_name "CoffeeBot"
282
- bot_icon ":coffee:"
283
-
284
- notification_text "It's a coffee emergency!"
285
- text "There's no coffee left!"
286
- end
287
- ```
288
-
289
- ### Testing
290
-
291
- You can do some basic testing against SlackMessage, at least if you use RSpec!
292
- You'll need to require and include the testing behavior like this, in your
293
- spec_helper file:
294
-
295
- ```ruby
296
- require 'slack_message/rspec'
297
-
298
- RSpec.configure do |config|
299
- include SlackMessage::RSpec
300
-
301
- # your other config
302
- end
303
- ```
304
-
305
- This will prevent API calls from leaking in your tests, and will allow you
306
- access to some custom matchers:
307
-
308
- ```ruby
309
- expect {
310
- SlackMessage.post_to('#general') { text "foo" }
311
- }.to post_slack_message_to('#general').with_content_matching(/foo/)
312
-
313
- expect {
314
- SlackMessage.post_as(:schmoebot) { text "foo" }
315
- }.to post_slack_message_as(:schmoebot)
316
-
317
- expect {
318
- SlackMessage.post_as(:schmoebot) { text "foo" }
319
- }.to post_slack_message_as('Schmoe Bot')
320
-
321
- expect {
322
- SlackMessage.post_as(:schmoebot) { text "foo" }
323
- }.to post_slack_message_with_icon(':schmoebot:')
324
-
325
- expect {
326
- SlackMessage.post_as(:schmoebot) { text "foo" }
327
- }.to post_slack_message_with_icon_matching(/gravatar/)
328
-
329
- expect {
330
- SlackMessage.post_to('#general') { text "foo" }
331
- }.to post_to_slack
332
- ```
333
-
334
- Be forewarned, I'm frankly not that great at more complicated RSpec matchers,
335
- so I'm guessing there are some bugs. Also, because the content of a message
336
- gets turned into a complex JSON object, matching against content isn't capable
337
- of very complicated regexes.
338
-
339
- What it Doesn't Do
340
- ------------
57
+ ### Opinionated Stances
341
58
 
342
59
  This gem is intended to stay simple. Other Slack gems have lots of config
343
60
  options and abilities, which makes them powerful, but makes them a pain to use.
344
- If you want to add a feature, open an issue on Github first to see if it's
345
- likely to be merged. This gem was built out of an existing need that _didn't_
346
- include all of the block API, but I'd be inclined to merge features that
347
- sustainably expand the DSL to include more useful features.
61
+
62
+ Accordingly, SlackMessage is developed with some strong opinions in mind:
63
+
64
+ * SlackMessage has no dependencies. Your lockfile is enough of a mess already.
65
+ * A DSL that focuses on code that is easy to write, read, and maintain. Only
66
+ features that can be implemented with that in mind are included.
67
+ * The code to build a message should look a lot like the message itself. Code
68
+ that is simple to read and understand is a priority.
69
+ * Webhooks are passé. Only Slack Apps are supported now.
70
+ * Unless you request otherwise, text is always rendered using `mrkdwn`. If you
71
+ want plaintext, you'll need to ask for it. Same for the `emoji` flag.
72
+ * As many API semantics as possible are hidden. For instance, if you post to
73
+ something that looks like an email address, `slack_message` is going to try
74
+ to look it up as an email address.
75
+ * A few little hacks on the block syntax, such as adding a `blank_line` (which
76
+ doesn't exist in the API), or leading spaces.
77
+ * Configuration is kept simple, with helpers for frequently reused bots.
348
78
 
349
79
  Some behaviors that are still planned but not yet added:
350
80
 
351
- * some API documentation amirite?
352
- * custom http_options in configuration
353
- * more of BlockKit's options
354
- * any interactive elements at all
355
- * editing / updating messages
356
- * multiple recipients
357
- * more interesting return types for your message
358
- * richer text formatting (for instance, `ul` is currently a hack)
359
- * more and better organized testing capability
81
+ * any interactive elements at all: https://api.slack.com/interactivity/handling
82
+ * multiple recipients: https://api.slack.com/methods/conversations.open
83
+ * more mrkdwn syntax, like quotes or code blocks
84
+ * more and better organized testing capability (scheduled messages, editing, deleting)
85
+ * posting ephemeral messages: https://api.slack.com/methods/chat.postEphemeral
360
86
 
361
- Contributing
362
- ------------
87
+ ### Contributing
363
88
 
364
- Contributions are very welcome. Fork, fix, submit pull.
89
+ Contributions are very welcome. Fork, fix, submit pull. Since simplicity of API is a strong priority, so opening an issue to discuss possible interface changes would be wise.
365
90
 
366
91
  Contribution is expected to conform to the [Contributor Covenant](https://github.com/jmmastey/slack_message/blob/master/CODE_OF_CONDUCT.md).
367
92
 
368
- License
369
- ------------
93
+ ### License
370
94
 
371
95
  This software is released under the [MIT License](https://github.com/jmmastey/slack_message/blob/master/MIT-LICENSE).
@@ -0,0 +1,116 @@
1
+ ## Getting Started / Configuration
2
+
3
+ To get started sending messages, you'll first need to create a Slack App with
4
+ some appropriate permissions. It used to be possible to use the Webhook API,
5
+ but that's long since been deprecated, and apps are pretty [straightforward to
6
+ create](https://api.slack.com/tutorials/tracks/getting-a-token).
7
+
8
+ Generally, make sure your token has permissions for _at least_ `users:read` and
9
+ `chat:write`. Then, define a default profile for SlackMessage to use for
10
+ posting.
11
+
12
+ ```ruby
13
+ SlackMessage.configure do |config|
14
+ api_token = 'xoxb-11111111111-2222222222-33333333333333333'
15
+
16
+ config.add_profile(api_token: api_token)
17
+ end
18
+ ```
19
+
20
+ You should keep your token in a safe place like `ENV`. If using this gem with
21
+ Rails, place this code in somewhere like
22
+ `config/initializers/slack_message.rb`.
23
+
24
+ ### Additional Profiles
25
+
26
+ If your app uses slack messages for several different purposes, it's common to
27
+ want to post to different channels as different names / icons / etc. To do that
28
+ more easily and consistently, you can specify multiple profiles.
29
+
30
+ ```ruby
31
+ SlackMessage.configure do |config|
32
+ api_token = 'xoxb-11111111111-2222222222-33333333333333333'
33
+
34
+ # default profile
35
+ config.add_profile(api_token: api_token, name: 'Slack Notifier')
36
+
37
+ # additional profiles (see below for usage)
38
+ config.add_profile(:prod_alert_bot,
39
+ name: 'Prod Alert Bot'
40
+ icon: ':mooseandsquirrel:'
41
+ )
42
+ config.add_profile(:sidekiq_bot,
43
+ api_token: ENV.fetch('SIDEKIQ_SLACK_APP_API_TOKEN'),
44
+ name: 'Sidekiq Bot',
45
+ )
46
+ end
47
+ ```
48
+
49
+ A number of parameters are available to make it simpler to use a profile
50
+ without specifying repetitive information. You can generally also specify this
51
+ information on a per-message basis.
52
+
53
+ | Config | Default | Value |
54
+ |-----------------|-----------------|-----------------------------------------------------------------|
55
+ | api_token | None | Your Slack App API Key. |
56
+ | name | From Slack App | The bot name for your message. |
57
+ | icon | From Slack App | Profile icon for your message. Specify as :emoji: or image URL. |
58
+ | default_channel | None (optional) | Channel / user to post to by default. |
59
+
60
+
61
+ Setting a `default_channel` specifically will allow you to use `post_as`, which
62
+ is a convenient shortcut for bots that repeatedly post to one channel as a
63
+ consistent identity.
64
+
65
+ ```ruby
66
+ SlackMessage.configure do |config|
67
+ config.add_profile(:red_alert_bot,
68
+ api_token: ENV.fetch('SLACK_API_TOKEN'),
69
+ name: 'Red Alerts',
70
+ icon: ':klaxon:',
71
+ default_channel: '#red_alerts'
72
+ )
73
+ end
74
+
75
+ SlackMessage.post_as(:red_alert_bot) do
76
+ text ":ambulance: weeooo weeooo something went wrong"
77
+ end
78
+ ```
79
+
80
+ There's no reason you can't use the same API key for several profiles. Profiles
81
+ are most useful to create consistent name / icon setups for apps with many
82
+ bots.
83
+
84
+ ### Debug Mode
85
+
86
+ If you'd like to get more information about the messages you send, you can set
87
+ SlackMessage to debug mode.
88
+
89
+ ```ruby
90
+ SlackMessage.configure do |config|
91
+ config.debug
92
+ end
93
+ ```
94
+
95
+ You will now see warnings detailing all params sent to the API.
96
+
97
+ ```ruby
98
+ {
99
+ :channel=>"#general",
100
+ :username=>"Builds",
101
+ :blocks=>[
102
+ {:type=>"section", :text=>{
103
+ :type=>"mrkdwn",
104
+ :text=>"Build Stability is Looking Ruff :dog:"
105
+ }}
106
+ ],
107
+ :text=>"Build Issues",
108
+ :post_at=>1639421171,
109
+ }
110
+ ```
111
+
112
+ Note this includes data that is not included in `SlackMessage.build`.
113
+
114
+ ---
115
+
116
+ Next: [Posting a Message](https://jmmastey.github.io/slack_message/02_posting_a_message)
@@ -0,0 +1,134 @@
1
+ ## Posting Messages
2
+
3
+ As mentioned at the outset, posting a message to Slack is dang easy.
4
+
5
+ ```ruby
6
+ SlackMessage.post_to('#general') do
7
+ text "We did it @here! :thumbsup:"
8
+ end
9
+ ```
10
+
11
+ That's it! SlackMessage will automatically serialize for the API.
12
+
13
+ ```json
14
+ [{"type":"section","text":{"type":"mrkdwn","text":"We did it @here! :thumbsup:"}}]
15
+ ```
16
+
17
+ Details like remembering that Slack made a mystifying decision to force you to
18
+ request "mrkdwn", or requiring your text to be wrapped into a section are
19
+ handled for you. Building up messages is meant to be as user-friendly as
20
+ possible.
21
+
22
+ ```ruby
23
+ SlackMessage.build do
24
+ text "haiku are easy"
25
+ text "but sometimes they don't make sense"
26
+ text "refrigerator"
27
+
28
+ context "- unknown author"
29
+ end
30
+ ```
31
+
32
+ SlackMessage will combine your text declarations and add any necessary wrappers
33
+ automatically.
34
+
35
+ ```json
36
+ [
37
+ {
38
+ "type": "section",
39
+ "text": {
40
+ "type": "mrkdwn",
41
+ "text": "haiku are easy\nbut sometimes they don't make sense\nrefrigerator"
42
+ }
43
+ },
44
+ {
45
+ "type": "context",
46
+ "elements": [
47
+ {
48
+ "type": "mrkdwn",
49
+ "text": "- unknown author"
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ ```
55
+
56
+ ### Direct Messages
57
+
58
+ It's just as easy to send messages directly to users. SlackMessage will look
59
+ for targets that are email-addressish, and look them up for you automatically.
60
+
61
+ ```ruby
62
+ SlackMessage.post_to('hello@joemastey.com') do
63
+ text "You specifically did it! :thumbsup:"
64
+ end
65
+ ```
66
+
67
+ SlackMessage will compose this into Block Kit syntax and send it on its way!
68
+
69
+ ### Multiple Profiles
70
+
71
+ If you've defined multiple profiles in configuration, you can specify which to
72
+ use for your message by specifying its name.
73
+
74
+ ```ruby
75
+ SlackMessage.post_to('#general', as: :sidekiq_bot) do
76
+ text ":octagonal_sign: A job has failed permanently and needs to be rescued."
77
+
78
+ link_button "Sidekiq Dashboard", sidekiq_dashboard_url, style: :danger
79
+ end
80
+ ```
81
+
82
+ You can also override profile bot details when sending a message.
83
+
84
+ ```ruby
85
+ SlackMessage.post_to('#general') do
86
+ bot_name "CoffeeBot"
87
+ bot_icon ":coffee:"
88
+
89
+ text ":coffee::clock: Time to take a break!"
90
+ end
91
+ ```
92
+
93
+ Finally, if your profile specifies a `default_channel`, you can also post with
94
+ the `post_as` shorthand.
95
+
96
+ ```ruby
97
+ SlackMessage.post_as(:coffeebot) do
98
+ text ":coffee::clock: Time to take a break!"
99
+ end
100
+ ```
101
+
102
+ ### Scheduling a Message
103
+
104
+ To schedule a message, simply provide a `at` parameter to your post. Provide
105
+ either a time object that responds to `to_i`, or an integer that represents a
106
+ [unix timestamp](https://en.wikipedia.org/wiki/Unix_time) for the time at which
107
+ you want your message posted.
108
+
109
+ ```ruby
110
+ SlackMessage.post_to('hello@joemastey.com', at: 20.seconds.from_now) do
111
+ text "From the top of the key. :basketball:"
112
+ end
113
+
114
+ SlackMessage.post_as(:basketball_bot, at: 20.seconds.from_now) do
115
+ text "Boom shakalaka! :explosion:"
116
+ end
117
+ ```
118
+
119
+ Please note that scheduled messages can't specify a `bot_name` or `bot_icon`,
120
+ nor can they be scheduled more than 120 days into the future.
121
+
122
+ ### Best Practices
123
+
124
+ Talk about having coherent methods that post a message, rather than a block
125
+ that includes lots of indirection or ternaries.
126
+
127
+ See the [API documentation for
128
+ chat.postMessage](https://api.slack.com/methods/chat.postMessage) or
129
+ [chat.scheduleMessage](https://api.slack.com/methods/chat.scheduleMessage) for
130
+ more information on posting messages.
131
+
132
+ ---
133
+
134
+ Next: [The SlackMessage DSL](https://jmmastey.github.io/slack_message/03_message_dsl)