slack_message 1.2.0 → 1.6.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.
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