slack_message 1.2.0 → 1.6.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: 30f694caf399c0408dab35d5f63be0dc5a06b0c3611f3fd43a9533877f5ca7b1
4
- data.tar.gz: 18a0dbd642a9b505ec21c114cf36fc36b9a4319c02a6f9fa057ac8abe6136957
3
+ metadata.gz: e66bdedefd2ac86c6c49d974e5f5d0474cc9b3756ce3a64e52df66ccc6e39cf4
4
+ data.tar.gz: b085edf556d957516d1cbbc9b260b7aff0e5d34b4561d27ae0d5f6b2dda9c93b
5
5
  SHA512:
6
- metadata.gz: 2768ef640f9e2ba0d79227c14f38c4c3288a218464251be81d4f9d182814b1b4540588b16a834e1077d45ce77a82da716de63ebb4fd0de513a261f4da2dd5abf
7
- data.tar.gz: a62d68742f30637398c4a337b9fd815c4b0f035aabe51a1d0be2693c3a72d2fbb8fcbe54cccd9c8e6983c44c1d199909f9e36792ba86d396764cf37549af2966
6
+ metadata.gz: ea935db68ca4771e11b40828d5cbd2fef02cf10c248fab3ede05ea82aef6a3a6d7ad96953debdc9214833ee0f281222e5e09adefd923c70d21090c996dba31a0
7
+ data.tar.gz: 46d2163aa9ec0e9df582700575d0c8b47b389b808f93275129025bc277086eb02fbeb4caa0754408dbc6d6fba9f06b6d8720493280550e0d3664bc735059f7c1
data/CHANGELOG.md CHANGED
@@ -2,11 +2,26 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.6.0] - 2021-10-04
6
+ - Added `:default_channel` and `post_as` to deal with repetitive channel usage.
7
+
8
+ ## [1.5.0] - 2021-10-01
9
+ - Added `ol` and `ul` to sections w/ some formatting.
10
+
11
+ ## [1.4.0] - 2021-09-27
12
+ - Moved image to accessory_image to differentiate between the image block
13
+ and the accessory image within a block.
14
+
15
+ ## [1.3.0] - 2021-09-27
16
+ - Added ability to use custom names when posting.
17
+ - Added ability to post images within sections.
18
+ - Added warnings for potentially invalid URLs.
19
+
5
20
  ## [1.2.0] - 2021-09-26
6
21
  - Turns out gemspec was broken. Fixed that.
7
22
 
8
23
  ## [1.1.0] - 2021-09-26
9
- - Expanded the README significantly w/ usage instructions
24
+ - Expanded the README significantly w/ usage instructions.
10
25
  - Added lots of error handling to requests.
11
26
 
12
27
  ## [1.0.0] - 2021-09-25
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slack_message (1.0.0)
4
+ slack_message (1.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -6,6 +6,14 @@ API](https://app.slack.com/block-kit-builder/) to make it easy to read and
6
6
  write messages to slack in your ruby application. It has zero dependencies and
7
7
  is built to be opinionated to keep your configuration needs low.
8
8
 
9
+ Posting a message to Slack should be this easy:
10
+
11
+ ```ruby
12
+ SlackMessage.post_to('#general') do
13
+ text "We did it @here! :thumbsup:"
14
+ end
15
+ ```
16
+
9
17
  To install, just add `slack_message` to your bundle and you're ready to go.
10
18
 
11
19
 
@@ -47,6 +55,28 @@ SlackMessage.configure do |config|
47
55
  end
48
56
  ```
49
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
+
50
80
  #### Configuring User Search
51
81
 
52
82
  Slack's API no longer allows you to send DMs to users by username. You need to
@@ -61,13 +91,13 @@ SlackMessage.configure do |config|
61
91
  end
62
92
  ```
63
93
 
64
- ### Usage
94
+ ### Posting Messages
65
95
 
66
- Basic usage is pretty straightforward:
96
+ As mentioned at the top, posting a message to Slack is dang easy:
67
97
 
68
98
  ```ruby
69
99
  SlackMessage.post_to('#general') do
70
- text "We did it! :thumbsup:"
100
+ text "We did it @here! :thumbsup:"
71
101
  end
72
102
  ```
73
103
 
@@ -130,7 +160,7 @@ SlackMessage is able to build all kinds of rich messages for you, and has been
130
160
  a real joy to use for the author at least. To understand a bit more about the
131
161
  possibilities of blocks, see Slack's [Block Kit
132
162
  Builder](https://app.slack.com/block-kit-builder/) to understand the structure
133
- better:
163
+ better. There are lots of options:
134
164
 
135
165
  ```ruby
136
166
  SlackMessage.post_to('#general') do
@@ -174,6 +204,27 @@ SlackMessage.post_to('#general', as: :sidekiq_bot) do
174
204
  end
175
205
  ```
176
206
 
207
+ You can also use a custom name when sending a message:
208
+
209
+ ```ruby
210
+ SlackMessage.post_to('#general') do
211
+ bot_name "CoffeeBot"
212
+
213
+ text ":coffee::clock: Time to take a break!"
214
+ end
215
+ ```
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.
177
228
 
178
229
  What it Doesn't Do
179
230
  ------------
@@ -190,7 +241,11 @@ DSL to include more of the block API itself.
190
241
  Also, some behaviors that are still planned but not yet added:
191
242
 
192
243
  * allow custom http_options in configuration
193
- * allow custom slack username per built message
244
+ * more of BlockKit's options
245
+ * any interactive elements at all (I don't understand them yet)
246
+ * more interesting return types for your message
247
+ * some way to specify default channel for a given profile (and omit param to post_to)
248
+ * richer text formatting (ul is currently a hack)
194
249
 
195
250
  Contributing
196
251
  ------------
@@ -27,19 +27,21 @@ 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
- warn("WARNING: Overriding profile '#{handle}' in SlackMessage config")
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
- def self.profile(handle)
38
+ def self.profile(handle, custom_name: nil)
39
39
  unless @@profiles.include?(handle)
40
40
  raise ArgumentError, "Unknown SlackMessage profile '#{handle}'."
41
41
  end
42
42
 
43
- @@profiles[handle]
43
+ @@profiles[handle].tap do |profile|
44
+ profile[:name] = custom_name if !custom_name.nil?
45
+ end
44
46
  end
45
47
  end
@@ -1,9 +1,12 @@
1
1
  class SlackMessage::Dsl
2
- attr_reader :body, :default_section
2
+ attr_reader :body, :default_section, :custom_bot_name
3
+
4
+ EMSPACE = " " # unicode emspace
3
5
 
4
6
  def initialize
5
7
  @body = []
6
8
  @default_section = Section.new
9
+ @custom_bot_name = nil
7
10
  end
8
11
 
9
12
  # allowable top-level entities within a block
@@ -24,6 +27,24 @@ class SlackMessage::Dsl
24
27
  @body.push({ type: "divider" })
25
28
  end
26
29
 
30
+ def image(url, alt_text:, title: nil)
31
+ finalize_default_section
32
+
33
+ config = {
34
+ type: "image",
35
+ image_url: url,
36
+ alt_text: alt_text,
37
+ }
38
+
39
+ if !title.nil?
40
+ config[:title] = {
41
+ type: "plain_text", text: title, emoji: true
42
+ }
43
+ end
44
+
45
+ @body.push(config)
46
+ end
47
+
27
48
  def context(text)
28
49
  finalize_default_section
29
50
 
@@ -38,12 +59,28 @@ class SlackMessage::Dsl
38
59
 
39
60
  def text(*args); default_section.text(*args); end
40
61
  def link_button(*args); default_section.link_button(*args); end
62
+ def accessory_image(*args); default_section.accessory_image(*args); end
41
63
  def blank_line(*args); default_section.blank_line(*args); end
42
64
  def link(*args); default_section.link(*args); end
43
65
  def list_item(*args); default_section.list_item(*args); end
66
+ def ul(*args); default_section.ul(*args); end
67
+ def ol(*args); default_section.ol(*args); end
44
68
 
45
69
  # end delegation
46
70
 
71
+ # custom bot name
72
+
73
+ def bot_name(name)
74
+ @custom_bot_name = name
75
+ end
76
+
77
+ # end bot name
78
+
79
+ def render
80
+ finalize_default_section
81
+ @body
82
+ end
83
+
47
84
  private
48
85
 
49
86
  # when doing things that would generate new top-levels, first try
@@ -56,11 +93,6 @@ class SlackMessage::Dsl
56
93
  @default_section = Section.new
57
94
  end
58
95
 
59
- def render
60
- finalize_default_section
61
- @body
62
- end
63
-
64
96
  class Section
65
97
  attr_reader :body
66
98
 
@@ -78,8 +110,31 @@ class SlackMessage::Dsl
78
110
  end
79
111
  end
80
112
 
113
+ def ul(elements)
114
+ raise Arguments, "please pass an array" unless elements.respond_to?(:map)
115
+ text(
116
+ elements.map { |text| "#{EMSPACE}• #{text}" }.join("\n")
117
+ )
118
+ end
119
+
120
+ def ol(elements)
121
+ raise Arguments, "please pass an array" unless elements.respond_to?(:map)
122
+ text(
123
+ elements.map.with_index(1) { |text, idx| "#{EMSPACE}#{idx}. #{text}" }.join("\n")
124
+ )
125
+ end
126
+
81
127
  # styles: default, primary, danger
82
128
  def link_button(label, target, style: :primary)
129
+ if !@body[:accessory].nil?
130
+ previous_type = @body[:accessory][:type]
131
+ warn "WARNING: Overriding previous #{previous_type} in section to use link_button instead: #{label}"
132
+ end
133
+
134
+ unless /(^|\s)((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)/i =~ target
135
+ warn "WARNING: Passing a probably-invalid URL to link button #{label} (url: '#{target}')"
136
+ end
137
+
83
138
  config = {
84
139
  accessory: {
85
140
  type: "button",
@@ -99,6 +154,24 @@ class SlackMessage::Dsl
99
154
  @body.merge!(config)
100
155
  end
101
156
 
157
+ def accessory_image(url, alt_text: nil)
158
+ if !@body[:accessory].nil?
159
+ previous_type = @body[:accessory][:type]
160
+ warn "WARNING: Overriding previous #{previous_type} in section to use accessory image instead: #{url}"
161
+ end
162
+
163
+ config = {
164
+ accessory: {
165
+ type: "image",
166
+ image_url: url
167
+ }
168
+ }
169
+
170
+ config[:accessory][:alt_text] = alt_text if !alt_text.nil?
171
+
172
+ @body.merge!(config)
173
+ end
174
+
102
175
  # for markdown links
103
176
  def link(label, target)
104
177
  "<#{target}|#{label}>"
@@ -109,7 +182,7 @@ class SlackMessage::Dsl
109
182
  end
110
183
 
111
184
  def blank_line
112
- text " " # unicode emspace
185
+ text EMSPACE
113
186
  end
114
187
 
115
188
  def has_content?
data/lib/slack_message.rb CHANGED
@@ -11,16 +11,35 @@ 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 = build(&block)
20
- profile = Configuration.profile(as)
19
+ payload = Dsl.new.tap do |instance|
20
+ instance.instance_eval(&block)
21
+ end
22
+
23
+ profile = Configuration.profile(as, custom_name: payload.custom_bot_name)
24
+ target = user_id_for(target) if target =~ /^\S{1,}@\S{2,}\.\S{2,}$/
25
+
26
+ Api.post(payload.render, target, profile)
27
+ end
28
+
29
+ def self.post_as(profile_name, &block)
30
+ payload = Dsl.new.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]
21
40
  target = user_id_for(target) if target =~ /^\S{1,}@\S{2,}\.\S{2,}$/
22
41
 
23
- Api.post(payload, target, profile)
42
+ Api.post(payload.render, target, profile)
24
43
  end
25
44
 
26
45
  def self.build(&block)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'slack_message'
3
- gem.version = "1.2.0"
3
+ gem.version = "1.6.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.2.0
4
+ version: 1.6.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-26 00:00:00.000000000 Z
11
+ date: 2021-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec