slack_message 1.3.0 → 1.7.0

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: fb63c39ef18b4b6e6fb1d25e62300fcff41b759f3d59902c10423c306f892007
4
- data.tar.gz: 499f1d885b3a00e60af92ff9d0ba17c19f59ba3b1468d178498d08802c9429dd
3
+ metadata.gz: a2cd232d81a66a48c9543a5b910c335bca7a82474a60472d03f7cffab3fce0d0
4
+ data.tar.gz: c27312311ff02ee414f2882461fe5ea9b5c07d9d8e99847ae7af33faf4a31283
5
5
  SHA512:
6
- metadata.gz: b0bf20b89e6ce48e9accb2ccd475d5f999686804d3c952e6a8903958af2f7b1500011f6abd904abba5f2cf73d635498f8c1feae7e4d00aa021b3ab0b6c1a5baa
7
- data.tar.gz: 42a8e2ecc5b6ca51ec1ab534e2a91bb500e352e26636f1a5671bf81244a40b321162bed30e1e7e0a78e53490575fbb0052c9d39fb108951f73425269cfafbab5
6
+ metadata.gz: 69352d5eb8d4f6837f66ba042817bfe0a51c3483356bbc64ded0cbc60fc7e72c084ea39df542a93bf79a6c0a8c4ad860cdb9791f28d807edb5b1c859b13f129f
7
+ data.tar.gz: 740af84829c6b258b4788b5f83901f242a5732e98737781efb288ee426ed232726823d9fdde453da6c7d83eb55607733e1d4b55757580676921b37abba1c70ad
data/CHANGELOG.md CHANGED
@@ -2,19 +2,33 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.7.0] - 2021-10-06
6
+ - Added new error messages when API configuration is wrong / missing.
7
+ - Fixed issue with `instance_eval` and using methods within block.
8
+ - Fixed issue with sectionless `list_item`.
9
+
10
+ ## [1.6.0] - 2021-10-04
11
+ - Added `:default_channel` and `post_as` to deal with repetitive channel usage.
12
+
13
+ ## [1.5.0] - 2021-10-01
14
+ - Added `ol` and `ul` to sections w/ some formatting.
15
+
16
+ ## [1.4.0] - 2021-09-27
17
+ - Changed `image` to `accessory_image` to differentiate between the image block
18
+ and the accessory image within a block.
19
+
5
20
  ## [1.3.0] - 2021-09-27
6
21
  - Added ability to use custom names when posting.
7
22
  - Added ability to post images within sections.
8
23
  - Added warnings for potentially invalid URLs.
9
24
 
10
25
  ## [1.2.0] - 2021-09-26
11
- - Turns out gemspec was broken. Fixed that.
26
+ - Fixed gemspec, which was entirely broken.
12
27
 
13
28
  ## [1.1.0] - 2021-09-26
14
29
  - Expanded the README significantly w/ usage instructions.
15
30
  - Added lots of error handling to requests.
16
31
 
17
32
  ## [1.0.0] - 2021-09-25
18
-
19
33
  - Added the base gem w/ a DSL for constructing blocks using sections.
20
34
  - Added a changelog, apparently.
data/README.md CHANGED
@@ -55,6 +55,28 @@ SlackMessage.configure do |config|
55
55
  end
56
56
  ```
57
57
 
58
+ If you frequently ping the same channel with the same bot, and don't want to
59
+ continually specify the channel name, you can specify a default channel and
60
+ post using the `post_as` method. It is otherwise identical to `post_to`, but
61
+ allows you to omit the channel argument:
62
+
63
+ ```ruby
64
+ SlackMessage.configure do |config|
65
+ config.add_profile(:prod_alert_bot,
66
+ name: 'Prod Alert Bot',
67
+ url: ENV['SLACK_PROD_ALERT_WEBHOOK_URL'],
68
+ default_channel: '#red_alerts'
69
+ )
70
+ end
71
+
72
+ SlackMessage.post_as(:prod_alert_bot) do
73
+ text ":ambulance: weeooo weeooo something went wrong"
74
+ end
75
+ ```
76
+
77
+ Note that `post_as` does not allow you to choose a channel (because that's just
78
+ the same as using `post_to`), so you really do have to specify `default_channel`.
79
+
58
80
  #### Configuring User Search
59
81
 
60
82
  Slack's API no longer allows you to send DMs to users by username. You need to
@@ -69,7 +91,7 @@ SlackMessage.configure do |config|
69
91
  end
70
92
  ```
71
93
 
72
- ### Usage
94
+ ### Posting Messages
73
95
 
74
96
  As mentioned at the top, posting a message to Slack is dang easy:
75
97
 
@@ -192,6 +214,18 @@ SlackMessage.post_to('#general') do
192
214
  end
193
215
  ```
194
216
 
217
+ Opinionated Stances
218
+ ------------
219
+
220
+ Slack's API has a lot of options available to you! But this gem takes some
221
+ opinionated stances on how to make use of that API. For instance:
222
+
223
+ * Unless you request otherwise, text is always rendered using `mrkdwn`. If you
224
+ want plaintext, you'll need to ask for it.
225
+ * Generally, same goes for the `emoji` flag on almost every text element.
226
+ * It's possible to ask for a `blank_line` in sections, even though that concept
227
+ isn't real. In this case, a text line containing only an emspace is rendered.
228
+
195
229
  What it Doesn't Do
196
230
  ------------
197
231
 
@@ -206,9 +240,12 @@ DSL to include more of the block API itself.
206
240
 
207
241
  Also, some behaviors that are still planned but not yet added:
208
242
 
243
+ * some API documentation amirite?
209
244
  * allow custom http_options in configuration
210
245
  * more of BlockKit's options
211
246
  * any interactive elements at all (I don't understand them yet)
247
+ * more interesting return types for your message
248
+ * richer text formatting (ul is currently a hack)
212
249
 
213
250
  Contributing
214
251
  ------------
@@ -17,9 +17,16 @@ class SlackMessage::Api
17
17
 
18
18
  if response.code != "200"
19
19
  raise "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
20
+ elsif response.body == ""
21
+ raise "Received empty 200 response from Slack when looking up user info. Check your API key."
22
+ end
23
+
24
+ begin
25
+ payload = JSON.parse(response.body)
26
+ rescue
27
+ raise "Unable to parse JSON response from Slack API\n#{response.body}"
20
28
  end
21
29
 
22
- payload = JSON.parse(response.body)
23
30
  if payload.include?("error") && payload["error"] == "invalid_auth"
24
31
  raise "Received an error because your authentication token isn't properly configured:\n#{response.body}"
25
32
  elsif payload.include?("error")
@@ -48,6 +55,8 @@ class SlackMessage::Api
48
55
  raise "Tried to send Slack message to non-existent channel or user '#{target}'"
49
56
  elsif response.body == "missing_text_or_fallback_or_attachments"
50
57
  raise "Tried to send Slack message with invalid payload."
58
+ elsif response.code == "302"
59
+ raise "Got 302 response while posting to Slack. Check your webhook URL for '#{profile[:handle]}'."
51
60
  elsif response.code != "200"
52
61
  raise "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
53
62
  end
@@ -27,12 +27,12 @@ module SlackMessage::Configuration
27
27
 
28
28
  ###
29
29
 
30
- def self.add_profile(handle = :default, name:, url:)
30
+ def self.add_profile(handle = :default, name:, url:, default_channel: nil)
31
31
  if @@profiles.include?(handle)
32
32
  warn "WARNING: Overriding profile '#{handle}' in SlackMessage config"
33
33
  end
34
34
 
35
- @@profiles[handle] = { name: name, url: url, handle: handle }
35
+ @@profiles[handle] = { name: name, url: url, handle: handle, default_channel: default_channel }
36
36
  end
37
37
 
38
38
  def self.profile(handle, custom_name: nil)
@@ -1,7 +1,13 @@
1
1
  class SlackMessage::Dsl
2
2
  attr_reader :body, :default_section, :custom_bot_name
3
3
 
4
- def initialize
4
+ EMSPACE = " " # unicode emspace
5
+
6
+ def initialize(block)
7
+ # Delegate missing methods to caller scope. Thanks 2008:
8
+ # https://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation
9
+ @caller_self = eval("self", block.binding
10
+
5
11
  @body = []
6
12
  @default_section = Section.new
7
13
  @custom_bot_name = nil
@@ -25,6 +31,24 @@ class SlackMessage::Dsl
25
31
  @body.push({ type: "divider" })
26
32
  end
27
33
 
34
+ def image(url, alt_text:, title: nil)
35
+ finalize_default_section
36
+
37
+ config = {
38
+ type: "image",
39
+ image_url: url,
40
+ alt_text: alt_text,
41
+ }
42
+
43
+ if !title.nil?
44
+ config[:title] = {
45
+ type: "plain_text", text: title, emoji: true
46
+ }
47
+ end
48
+
49
+ @body.push(config)
50
+ end
51
+
28
52
  def context(text)
29
53
  finalize_default_section
30
54
 
@@ -39,10 +63,12 @@ class SlackMessage::Dsl
39
63
 
40
64
  def text(*args); default_section.text(*args); end
41
65
  def link_button(*args); default_section.link_button(*args); end
42
- def image(*args); default_section.image(*args); end
66
+ def accessory_image(*args); default_section.accessory_image(*args); end
43
67
  def blank_line(*args); default_section.blank_line(*args); end
44
68
  def link(*args); default_section.link(*args); end
45
69
  def list_item(*args); default_section.list_item(*args); end
70
+ def ul(*args); default_section.ul(*args); end
71
+ def ol(*args); default_section.ol(*args); end
46
72
 
47
73
  # end delegation
48
74
 
@@ -59,13 +85,17 @@ class SlackMessage::Dsl
59
85
  @body
60
86
  end
61
87
 
88
+ def method_missing(meth, *args, &blk)
89
+ @caller_self.send meth, *args, &blk
90
+ end
91
+
62
92
  private
63
93
 
64
94
  # when doing things that would generate new top-levels, first try
65
95
  # to finish the implicit section.
66
96
  def finalize_default_section
67
97
  if default_section.has_content?
68
- @body.push(default_section.body)
98
+ @body.push(default_section.render)
69
99
  end
70
100
 
71
101
  @default_section = Section.new
@@ -88,6 +118,20 @@ class SlackMessage::Dsl
88
118
  end
89
119
  end
90
120
 
121
+ def ul(elements)
122
+ raise Arguments, "please pass an array" unless elements.respond_to?(:map)
123
+ text(
124
+ elements.map { |text| "#{EMSPACE}• #{text}" }.join("\n")
125
+ )
126
+ end
127
+
128
+ def ol(elements)
129
+ raise Arguments, "please pass an array" unless elements.respond_to?(:map)
130
+ text(
131
+ elements.map.with_index(1) { |text, idx| "#{EMSPACE}#{idx}. #{text}" }.join("\n")
132
+ )
133
+ end
134
+
91
135
  # styles: default, primary, danger
92
136
  def link_button(label, target, style: :primary)
93
137
  if !@body[:accessory].nil?
@@ -118,10 +162,10 @@ class SlackMessage::Dsl
118
162
  @body.merge!(config)
119
163
  end
120
164
 
121
- def image(url, alt_text: nil)
165
+ def accessory_image(url, alt_text: nil)
122
166
  if !@body[:accessory].nil?
123
167
  previous_type = @body[:accessory][:type]
124
- warn "WARNING: Overriding previous #{previous_type} in section to use image instead: #{url}"
168
+ warn "WARNING: Overriding previous #{previous_type} in section to use accessory image instead: #{url}"
125
169
  end
126
170
 
127
171
  config = {
@@ -146,7 +190,7 @@ class SlackMessage::Dsl
146
190
  end
147
191
 
148
192
  def blank_line
149
- text " " # unicode emspace
193
+ text EMSPACE
150
194
  end
151
195
 
152
196
  def has_content?
data/lib/slack_message.rb CHANGED
@@ -11,12 +11,12 @@ module SlackMessage
11
11
  configuration.configure(&block)
12
12
  end
13
13
 
14
- def self.user_id_for(email)
14
+ def self.user_id_for(email) # spooky undocumented public method 👻
15
15
  Api::user_id_for(email)
16
16
  end
17
17
 
18
18
  def self.post_to(target, as: :default, &block)
19
- payload = Dsl.new.tap do |instance|
19
+ payload = Dsl.new(block).tap do |instance|
20
20
  instance.instance_eval(&block)
21
21
  end
22
22
 
@@ -26,8 +26,24 @@ module SlackMessage
26
26
  Api.post(payload.render, target, profile)
27
27
  end
28
28
 
29
+ def self.post_as(profile_name, &block)
30
+ payload = Dsl.new(block).tap do |instance|
31
+ instance.instance_eval(&block)
32
+ end
33
+
34
+ profile = Configuration.profile(profile_name, custom_name: payload.custom_bot_name)
35
+ if profile[:default_channel].nil?
36
+ raise ArgumentError, "Sorry, you need to specify a default_channel for profile #{profile_name} to use post_as"
37
+ end
38
+
39
+ target = profile[:default_channel]
40
+ target = user_id_for(target) if target =~ /^\S{1,}@\S{2,}\.\S{2,}$/
41
+
42
+ Api.post(payload.render, target, profile)
43
+ end
44
+
29
45
  def self.build(&block)
30
- Dsl.new.tap do |instance|
46
+ Dsl.new(block).tap do |instance|
31
47
  instance.instance_eval(&block)
32
48
  end.send(:render)
33
49
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'slack_message'
3
- gem.version = "1.3.0"
3
+ gem.version = "1.7.0"
4
4
  gem.summary = "A nice DSL for composing rich messages in Slack"
5
5
  gem.authors = ["Joe Mastey"]
6
6
  gem.email = 'hello@joemastey.com'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack_message
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Mastey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-27 00:00:00.000000000 Z
11
+ date: 2021-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec