slack_message 2.4.0 → 3.0.2

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,387 @@
1
+ ## The Message DSL
2
+
3
+ A pretty good number of the elements available in BlockKit are usable in
4
+ SlackMessage. There are also a few elements that haven't been implemented in
5
+ the official API, but are too useful to be missing.
6
+
7
+ ### Basic Text
8
+
9
+ While BlockKit officially requires that any elements are contained within a
10
+ section element, that requirement is relaxed in SlackMessage. If you don't
11
+ specify a section, one will silently be created to encapsulate your code.
12
+ That's the secret behind the most basic messages in these docs.
13
+
14
+ ```ruby
15
+ SlackMessage.build do
16
+ text "couldn't be easier"
17
+ end
18
+
19
+ # => [{:type=>"section",
20
+ # :text=>{:type=>"mrkdwn", :text=>"couldn't be easier"}
21
+ # }]
22
+ ```
23
+
24
+ This is equivalent to the more verbose version with a declared section.
25
+
26
+ ```ruby
27
+ SlackMessage.build do
28
+ section do
29
+ text "could be easier"
30
+ end
31
+ end
32
+
33
+ # => [{:type=>"section",
34
+ # :text=>{:type=>"mrkdwn", :text=>"could be easier"}
35
+ # }]
36
+ ```
37
+
38
+ Text elements are the most basic type of element. Adding multiple text calls
39
+ will add a newline between text calls, which will cause a line break
40
+ appropriately.
41
+
42
+ ```ruby
43
+ SlackMessage.build do
44
+ text "one fish, two fish"
45
+ text "red fish, blue fish"
46
+ end
47
+
48
+ # => [{:type=>"section",
49
+ # :text=>{:type=>"mrkdwn", :text=>"one fish, two fish\nred fish, blue fish"}
50
+ # }]
51
+ ```
52
+
53
+ Slack uses a [faux-markdown syntax called
54
+ mrkdwn](https://api.slack.com/reference/surfaces/formatting#basics), which you
55
+ may be familiar with by typing in the Slack app itself. The API will
56
+ automatically render mrkdwn appropriately.
57
+
58
+ ```ruby
59
+ SlackMessage.build do
60
+ text "*Favorite Colors*"
61
+ text "_John_: ~red~ actually blue."
62
+ end
63
+
64
+ # => [{:type=>"section",
65
+ # :text=>{:type=>"mrkdwn", :text=>"*Favorite Colors*\n_John_: ~red~ actually blue."}}]
66
+ ```
67
+
68
+ Rendering emoji in messages is possible using either a) real unicode emoji in
69
+ your message, or b) using the `:emojiname:` syntax, which supports any emoji
70
+ that would work in your Slack app itself, including custom emoji.
71
+
72
+ ```ruby
73
+ SlackMessage.build do
74
+ text ":shipit_squirrel:🚀 time to gooo :tada:"
75
+ end
76
+
77
+ # => [{:type=>"section",
78
+ # :text=>{:type=>"mrkdwn", :text=>":shipit_squirrel:🚀 time to gooo :tada:"}
79
+ # }]
80
+ ```
81
+
82
+ To add a link using Slack's non-markdown link syntax, use the `link` helper
83
+ method interpolated into a text element. Using the `link` helper as its own
84
+ element won't work, as the method simply returns a string that has to be
85
+ included into a text element specifically.
86
+
87
+ ```ruby
88
+ SlackMessage.build do
89
+ text "Your #{link('build', 'https://google.com')} is ready."
90
+ end
91
+
92
+ # => [{:type=>"section",
93
+ # :text=>{:type=>"mrkdwn", :text=>"Your <https://google.com|build> is ready."}
94
+ # }]
95
+ ```
96
+
97
+ While the API squishes whitespace (much in the same way HTML does), it may
98
+ sometimes be useful to add a blank line between text _without_ adding a new
99
+ section to your message. To do so, use the pseudo-element `blank_line`.
100
+
101
+ ```ruby
102
+ SlackMessage.build do
103
+ text "don't let this line"
104
+ blank_line
105
+ text "touch this line."
106
+ end
107
+
108
+ # => => [{:type=>"section",
109
+ # :text=>{:type=>"mrkdwn", :text=>"don't let this line\n \ntouch this line."}
110
+ # }]
111
+ ```
112
+
113
+ Note that between the two newlines in the above example is a unicode emspace,
114
+ which the API will respect as a line worth rendering.
115
+
116
+ ### Explicitly Declared Sections
117
+
118
+ Adding more sections is trivial. Simply declare each section and it will be
119
+ separated in the rendered message. This can often occur when looping.
120
+
121
+ ```ruby
122
+ SlackMessage.build do
123
+ pet_types.each do |type, breeds|
124
+ section do
125
+ text "*#{type}:* #{breeds.join(", ")}"
126
+ end
127
+ end
128
+ end
129
+ ```
130
+
131
+ It can also be useful to add a visual divider (similar to an `hr` in HTML)
132
+ between sections. To add one of these, use the `divider` helper. You can also
133
+ add a divider at the end of all the sections, but it often looks silly.
134
+
135
+ ```ruby
136
+ SlackMessage.build do
137
+ section do
138
+ text "*Topsiders:* Emily, Elsie, Derick"
139
+ end
140
+
141
+ divider
142
+
143
+ section do
144
+ text "*Undergrounders:* Kristina, Lauren, Different Emily"
145
+ end
146
+ end
147
+
148
+ # => [
149
+ # {:type=>"section", :text=>{:type=>"mrkdwn", :text=>"*Topsiders:* Emily, Elsie, Derick"}},
150
+ # {:type=>"divider"},
151
+ # {:type=>"section", :text=>{:type=>"mrkdwn", :text=>"*Undergrounders:* Kristina, Lauren, Different Emily"}}
152
+ # ]
153
+ ```
154
+
155
+ Note that a divider can only occur between sections, not within a single
156
+ section. Because of how implicit sections are built, it may look like this
157
+ works for simple messages. But, you may have troubles when you start adding
158
+ more complicated elements to your messages.
159
+
160
+ ### Buttons
161
+
162
+ BlockKit allows you to specify a button to the right of a section / block. That
163
+ button will be aligned outside the normal space for a section, and is meant to
164
+ link out of the app. To create one of these, use the `link_button` helper.
165
+
166
+ ```ruby
167
+ SlackMessage.build do
168
+ text "Your daily stats are ready @here"
169
+ link_button "Stats Dashboard", stats_dashboard_url
170
+ end
171
+
172
+ # => [{:type=>"section",
173
+ # :text=>{:type=>"mrkdwn", :text=>"Your daily stats are ready @here"},
174
+ # :accessory=>
175
+ # {:type=>"button",
176
+ # :url=>"http://yoursite.com/stats_dashboard",
177
+ # :text=>{:type=>"plain_text", :text=>"Stats Dashboard", :emoji=>true},
178
+ # :style=>:primary}}]
179
+ ```
180
+
181
+ Slack allows three styles for buttons: `default`, `primary`, and `danger`.
182
+ These correspond to gray, green and red buttons respectively. If not specified,
183
+ SlackMessage will use the `primary` style for buttons. I get that this could be
184
+ confusing when there is a style specifically named default, but in my
185
+ experience, a colorful button is way more common.
186
+
187
+ You can override button style by specifying the style with your link button.
188
+
189
+ ```ruby
190
+ SlackMessage.build do
191
+ text "A job has failed catastrophically!"
192
+ link_button "Sidekiq Dashboard", sidekiq_dashboard_url, style: :danger
193
+ end
194
+
195
+ # => [{:type=>"section",
196
+ # :text=>{:type=>"mrkdwn", :text=>"A job has failed catastrophically!"},
197
+ # :accessory=>
198
+ # {:type=>"button",
199
+ # :url=>"https://yoursite.com/sidekiq",
200
+ # :text=>{:type=>"plain_text", :text=>"Sidekiq Dashboard", :emoji=>true},
201
+ # :style=>:danger}}]
202
+ ```
203
+
204
+ ### Ordered and Unordered Lists
205
+
206
+ The Slack API doesn't have native support for HTML-style ordered and unordered
207
+ lists, but there are convenience methods in SlackMessage to render a close
208
+ approximation.
209
+
210
+ ```ruby
211
+ SlackMessage.build do
212
+ section do
213
+ text '*Pet Goodness Tiers*'
214
+
215
+ ol([
216
+ 'tiny pigs',
217
+ 'reptiles',
218
+ 'dogs',
219
+ 'cats',
220
+ ])
221
+ end
222
+
223
+ section do
224
+ text '_voted by_'
225
+ ul(['Joe', 'Emily', 'Sophia', 'Matt'])
226
+ end
227
+ end
228
+ ```
229
+
230
+ Because Slack automatically collapses leading whitespace, indention of lists is
231
+ handled using unicode emspaces. Bullets for unordered lists are also unicode
232
+ characters to avoid being read as markdown.
233
+
234
+ ### List Items (e.g. HTML dt & dd)
235
+
236
+ When trying to represent title / value lists, you can use the "list item" block
237
+ type to pass a set of values. Slack does not allow you to customize how many
238
+ items are shown per line, so you'll just have to work with it.
239
+
240
+ ```ruby
241
+ SlackMessage.build do
242
+ text 'Import results are available!'
243
+
244
+ list_item 'Import Date', Date.today.to_s
245
+ list_item 'Items Imported', 55_000
246
+ list_item 'Errors', 23
247
+ list_item 'Bad Values', errors.map(&:to_s)
248
+ end
249
+ ```
250
+
251
+ ### Images and Accessory Images
252
+
253
+ There are two main types of images in Slack: the
254
+ [image](https://imgur.com/XEUap1r) and the [accessory
255
+ image](https://imgur.com/zuhjBDq). In short, `accessory_image` is part of a
256
+ section itself and is shown alongside an existing block, while `image` is shown
257
+ as its own top-level element.
258
+
259
+ Accordingly, an accessory image should be used within a section. An accessory
260
+ image can accept alt-text, which is also a best practice, for usability
261
+ reasons.
262
+
263
+ ```ruby
264
+ SlackMessage.build do
265
+ section do
266
+ text 'Looks like the coffee machine is empty.'
267
+ accessory_image 'https://your.com/empty_coffee_logo.jpg', alt_text: 'logo of a forlorn coffee cup'
268
+ end
269
+ end
270
+ ```
271
+
272
+ Only one accessory image can be used per section, and declaring more will issue
273
+ a warning and simply override the previous accessory image.
274
+
275
+ By contrast, `image` can be used many times, and will create a new top-level
276
+ section for each call. Image accepts alt-text, but also a title, which will
277
+ be displayed above the image (along with an icon to collapse the image).
278
+
279
+ ```ruby
280
+ SlackMessage.build do
281
+ section do
282
+ text 'Most Recent Tiny Pig Images'
283
+ end
284
+
285
+ image 'https://your.com/employee_pets/best/pig_1.jpg', alt_text: 'a tiny pig eating ice cream', title: 'Spider Pig'
286
+ image 'https://your.com/employee_pets/best/pig_2.jpg', alt_text: 'a tiny pig smiling mischeviously', title: 'Porkeypine'
287
+ image 'https://your.com/employee_pets/best/pig_3.jpg', alt_text: 'a tiny pig with wellies and an umbrella', title: 'Albert Sweinstein'
288
+ end
289
+ ```
290
+
291
+ Sectionless messages can also use `accessory_image`, but this can get confusing
292
+ since they could potentially be interspersed with top-level images, so I
293
+ wouldn't recommend it.
294
+
295
+ ```ruby
296
+ # the difference between these two image styles is confusing, and the call
297
+ # to `image` closed the current section and started a new one.
298
+ SlackMessage.build do
299
+ text 'Looks like the coffee machine is empty.'
300
+ accessory_image 'https://your.com/empty_coffee_logo.jpg'
301
+
302
+ text '*Most Recent Coffee Maker Surveillance Photo*'
303
+ image 'https://your.com/surveillance/coffee/current.jpg'
304
+ end
305
+ ```
306
+
307
+ ### Footers (Context)
308
+
309
+ Slack allows you to add a small additional piece of text to your message, which
310
+ will be rendered in italics and small text. It can support both links and
311
+ emoji, and is useful for providing minor details for your message.
312
+
313
+ ```ruby
314
+ SlackMessage.build do
315
+ text "New coffee complaints have been added."
316
+ context "this complaint added by #{link('Joe Mastey', 'hello@joemastey.com')}."
317
+ end
318
+
319
+ # => [{:type=>"section",
320
+ # :text=>{:type=>"mrkdwn", :text=>"New coffee complaints have been added."}
321
+ # },
322
+ # {:type=>"context", :elements=>
323
+ # [{:type=>"mrkdwn",
324
+ # :text=>"this complaint added by <hello@joemastey.com|Joe Mastey>."
325
+ # }]
326
+ # }]
327
+ ```
328
+
329
+ Context does not belong to a section, and only one can be added to your entire
330
+ slack message. Specifying another `context` will issue a warning and overwrite
331
+ any previous call.
332
+
333
+ ### Bot Customization
334
+
335
+ By default - and with scheduled messages - Slack will use the name and icon of
336
+ the Slack app whose API key you configured. As seen before, it's possible to
337
+ override those default names and icons in configuration. However, it can also
338
+ be customized per-message.
339
+
340
+ ```ruby
341
+ SlackMessage.build do
342
+ bot_icon ":sad_robot:"
343
+ bot_name "BadNewsBuildBot"
344
+
345
+ text "The build is broken. @here"
346
+ end
347
+
348
+ # => [{:type=>"section", :text=>{:type=>"mrkdwn", :text=>"The build is broken. @here"}}]
349
+ ```
350
+
351
+ Notice that the bot details aren't shown in the output of the `build` command.
352
+ To view the change to the message payload from these calls, use `debug` mode.
353
+
354
+ The `bot_icon` can be specified as either an emoji (`:shipit:`), or a URL
355
+ pointing to an image (`http://mysite.com/shipit.png`). Any other value seems to
356
+ cause an error.
357
+
358
+ ### Custom Notification Text
359
+
360
+ For users who have notifications turned on, Slack will provide a small message
361
+ preview when you send them a message. By default, this preview will take the
362
+ first several words from your message.
363
+
364
+ However, you can specify some custom notification text to be shown to the user.
365
+ This text supports basic emoji and formatting, but nothing complicated.
366
+
367
+ ```ruby
368
+ SlackMessage.build do
369
+ notification_text "Having issues with the build. :ohnoes:"
370
+
371
+ text "The build is broken. The error message was 'undefined method round for NilClass'"
372
+
373
+ # => [{:type=>"section",
374
+ # :text=>
375
+ # {:type=>"mrkdwn",
376
+ # :text=>"The build is broken. The error message was 'undefined method round for NilClass'"}}]
377
+ end
378
+ ```
379
+
380
+ Again notice that notification text is not set within the blocks themselves, so
381
+ you will need to enable debugging to see how it changes what is sent to the
382
+ API. Only one custom notification is allowed, so further calls will issue a
383
+ warning and replace the previous notification text.
384
+
385
+ ---
386
+
387
+ Next: [Editing Messages](https://jmmastey.github.io/slack_message/04_editing_messages)
@@ -0,0 +1,87 @@
1
+ ## Updating a Previous Message
2
+
3
+ After you've posted a message, you may want to edit it later. Interactive bots,
4
+ for instance, may want to repeatedly update a message.
5
+
6
+ Posting will always return an object representing your posted message.
7
+
8
+ ```ruby
9
+ message = SlackMessage.post_to('#general') do
10
+ text "Getting ready..."
11
+ end
12
+ ```
13
+
14
+ Then, you can use that response object to go back and rewrite the message a
15
+ little or a lot.
16
+
17
+ ```ruby
18
+ SlackMessage.update(message) do
19
+ text "Done!"
20
+ end
21
+ ```
22
+
23
+ The new message contents will be built and updated via the API. To give an
24
+ example, you could alert slack to a job status by updating your original
25
+ message.
26
+
27
+
28
+ ```ruby
29
+ class SomeWorker < ApplicationWorker
30
+ def perform
31
+ post_started_status
32
+
33
+ # ... perform work here
34
+
35
+ post_finished_status
36
+ end
37
+
38
+ private
39
+
40
+ def post_started_status
41
+ @message = SlackMessage.post_as(:job_worker) do
42
+ text "Beginning upload."
43
+ end
44
+ end
45
+
46
+ def post_finished_status
47
+ SlackMessage.update(@message) do
48
+ text "Finished upload! @here come and get it."
49
+ link_button "See Results", uploaded_data_url
50
+ end
51
+ end
52
+ end
53
+ ```
54
+
55
+ ### Storing Response Objects for Later
56
+
57
+ Since updates are likely to occur long after you post the original message, you
58
+ may want to persist a reference to the message until you need to update it
59
+ later. As one option, you could serialize the response object for later.
60
+
61
+ ```ruby
62
+ # initially
63
+ message = SlackMessage.post_to('#general') do
64
+ text "Starting..."
65
+ end
66
+ redis_connection.set(self.message_cache_key, Marshal.dump(message))
67
+
68
+
69
+ # later
70
+ message = Marshal.load(redis_connection.get(self.message_cache_key))
71
+ SlackMessage.update(message) do
72
+ text "Finished!"
73
+ end
74
+ ```
75
+
76
+ ### Updating Scheduled Messages
77
+
78
+ Sadly, there's currently no way to edit a scheduled message. You'll receive an
79
+ error if you attempt to call `update` on a scheduled message.
80
+
81
+ See the [API documentation for
82
+ chat.update](https://api.slack.com/methods/chat.update) for more information on
83
+ updating messages.
84
+
85
+ ---
86
+
87
+ Next: [Deleting Messages](https://jmmastey.github.io/slack_message/05_deleting_messages)
@@ -0,0 +1,45 @@
1
+ ## Deleting Messages
2
+
3
+ Deleting a message is much like editing a message, only simpler. Just like when
4
+ you edit a message, you'll need a reference to the message you posted.
5
+
6
+ ```ruby
7
+ message = SlackMessage.post_to('#general') do
8
+ text "Testing: #{SLACK_SECRET_KEY}"
9
+ end
10
+ ```
11
+
12
+ Then you can simply call the `delete` method to make up for your mistakes.
13
+
14
+ ```ruby
15
+ SlackMessage.delete(message)
16
+ ```
17
+
18
+ *Important Note: It's not possible to delete a message sent directly to a user.
19
+ It's also not possible to delete a scheduled message once it's already posted.
20
+ Don't send anything you don't want your boss to read.*
21
+
22
+ As with editing a message, it's possible to persist messages to redis / your
23
+ database to be removed at a later date.
24
+
25
+ ```ruby
26
+ # initially
27
+ message = SlackMessage.post_to('#general') do
28
+ text "Testing: #{SLACK_SECRET_KEY}"
29
+ end
30
+ redis_connection.set(self.message_cache_key, Marshal.dump(message))
31
+
32
+
33
+ # later
34
+ message = Marshal.load(redis_connection.get(self.message_cache_key))
35
+ SlackMessage.delete(message)
36
+ ```
37
+
38
+ See the [API documentation for
39
+ chat.delete](https://api.slack.com/methods/chat.delete) or
40
+ [chat.deleteScheduledMessage](https://api.slack.com/methods/chat.deleteScheduledMessage)
41
+ for more information on deleting messages.
42
+
43
+ ---
44
+
45
+ Next: [Mentions / Notifying Users](https://jmmastey.github.io/slack_message/06_notifying_users)
@@ -0,0 +1,62 @@
1
+ ## Mentions / Notifying Users
2
+
3
+ There are several supported ways to tag and notify users. As mentioned
4
+ initially, it's possible to DM a user by their account email.
5
+
6
+ ```ruby
7
+ SlackMessage.post_to('hello@joemastey.com') do
8
+ text "Hi there!"
9
+ end
10
+ ```
11
+
12
+ You can also mention a user by email within a channel by wrapping their name in
13
+ tags.
14
+
15
+ ```ruby
16
+ SlackMessage.post_to('#general') do
17
+ bot_name "CoffeeBot"
18
+ bot_icon ":coffee:"
19
+
20
+ text ":coffee: It's your turn to make coffee <hello@joemastey.com>."
21
+ end
22
+ ```
23
+
24
+ Emails that are not wrapped in tags will be rendered as normal email addresses.
25
+ Additionally, Slack will automatically convert a number of channel names and
26
+ tags you're probably already used to.
27
+
28
+ ```ruby
29
+ SlackMessage.post_to('#general') do
30
+ bot_name "CoffeeBot"
31
+ bot_icon ":coffee:"
32
+
33
+ text "@here There's no coffee left! Let #general know when you fix it."
34
+ end
35
+ ```
36
+
37
+ By default, the desktop notification for a message will be the text of the
38
+ message itself. However, you can customize desktop notifications if you prefer.
39
+
40
+ ```ruby
41
+ SlackMessage.post_to('hello@joemastey.com') do
42
+ bot_name "CoffeeBot"
43
+ bot_icon ":coffee:"
44
+
45
+ notification_text "It's a coffee emergency!"
46
+ text "There's no coffee left!"
47
+ end
48
+ ```
49
+
50
+ ### Using @channel or @here
51
+
52
+ Not really a feature, but Slack will respect usage of `@here` and `@channel`.
53
+
54
+ ```ruby
55
+ SlackMessage.post_to('#general') do
56
+ text "Hey @channel, don't forget to submit your drink requests."
57
+ end
58
+ ```
59
+
60
+ ---
61
+
62
+ Next: [Testing](https://jmmastey.github.io/slack_message/07_testing)
@@ -0,0 +1,49 @@
1
+ ## Testing
2
+
3
+ You can do some basic testing against SlackMessage, at least if you use RSpec!
4
+ You'll need to require and include the testing behavior in your spec_helper
5
+ file.
6
+
7
+ ```ruby
8
+ require 'slack_message/rspec'
9
+
10
+ RSpec.configure do |config|
11
+ include SlackMessage::RSpec
12
+
13
+ # your other spec_helper config
14
+ end
15
+ ```
16
+
17
+ This will prevent API calls from leaking in your tests, and will allow you
18
+ access to some custom matchers.
19
+
20
+ ```ruby
21
+ expect {
22
+ SlackMessage.post_to('#general') { text "foo" }
23
+ }.to post_slack_message_to('#general').with_content_matching(/foo/)
24
+
25
+ expect {
26
+ SlackMessage.post_as(:schmoebot) { text "foo" }
27
+ }.to post_slack_message_as(:schmoebot)
28
+
29
+ expect {
30
+ SlackMessage.post_as(:schmoebot) { text "foo" }
31
+ }.to post_slack_message_as('Schmoe Bot')
32
+
33
+ expect {
34
+ SlackMessage.post_as(:schmoebot) { text "foo" }
35
+ }.to post_slack_message_with_icon(':schmoebot:')
36
+
37
+ expect {
38
+ SlackMessage.post_as(:schmoebot) { text "foo" }
39
+ }.to post_slack_message_with_icon_matching(/gravatar/)
40
+
41
+ expect {
42
+ SlackMessage.post_to('#general') { text "foo" }
43
+ }.to post_to_slack
44
+ ```
45
+
46
+ Be forewarned, I'm frankly not that great at more complicated RSpec matchers,
47
+ so I'm guessing there are some bugs. Also, because the content of a message
48
+ gets turned into a complex JSON object, matching against content isn't capable
49
+ of very complicated regexes.
data/docs/_config.yml ADDED
@@ -0,0 +1,6 @@
1
+ plugins:
2
+ - jekyll-relative-links
3
+ relative_links:
4
+ enabled: true
5
+ collections: true
6
+ theme: jekyll-theme-midnight
data/docs/index.md ADDED
@@ -0,0 +1,53 @@
1
+ * [Getting Started / Configuration](https://jmmastey.github.io/slack_message/01_configuration)
2
+ * [Posting a Message](https://jmmastey.github.io/slack_message/02_posting_a_message)
3
+ * [The SlackMessage DSL](https://jmmastey.github.io/slack_message/03_message_dsl)
4
+ * [Editing Messages](https://jmmastey.github.io/slack_message/04_editing_messages)
5
+ * [Deleting Messages](https://jmmastey.github.io/slack_message/05_deleting_messages)
6
+ * [Mentions / Notifying Users](https://jmmastey.github.io/slack_message/06_notifying_users)
7
+ * [Testing](https://jmmastey.github.io/slack_message/07_testing)
8
+
9
+ SlackMessage is a gem that makes it easy to send messages to Slack from your
10
+ application. _Really_ easy.
11
+
12
+ ```ruby
13
+ SlackMessage.post_to('#general') do
14
+ text "We did it @here! :thumbsup:"
15
+ end
16
+ ```
17
+
18
+ And not just simple messages. You can compose complicated messages quickly in a
19
+ DSL that's focused on usability and maintainability. It can be tough to
20
+ maintain code in other similar gems, but not here.
21
+
22
+ ```ruby
23
+ SlackMessage.post_to('hello@joemastey.com') do
24
+ section do
25
+ text "A job has generated some output for you to review."
26
+ text 'And More' * 10
27
+ link_button "See Results", "https://google.com"
28
+ end
29
+
30
+ section do
31
+ text ":unlock-new: New Data Summary"
32
+
33
+ list_item "Date", "09/05/2021"
34
+ list_item "Total Imported", 45_004
35
+ list_item "Total Errors", 5
36
+ end
37
+
38
+ divider
39
+
40
+ section do
41
+ text "See more here: #{link('result', 'https://google.com')}"
42
+ end
43
+
44
+ context "Kicked off by <hello@joemastey.com> at **9:05am**"
45
+ end
46
+ ```
47
+
48
+ It has no dependencies and minimal configuration needs, so you can get up and
49
+ running quickly.
50
+
51
+ ---
52
+
53
+ Next: [Get Started](https://jmmastey.github.io/slack_message/01_configuration)