slacks 0.4.2 → 0.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
- SHA1:
3
- metadata.gz: 4655b64b95738df424e627dd671d219ee46c55e3
4
- data.tar.gz: d5f1d21638a975aeb802d17a2b00d814b14579f3
2
+ SHA256:
3
+ metadata.gz: 3042bf152b61c2caa8a3b4fe792b49822d46915712a8573f6bcafc86132ae2b8
4
+ data.tar.gz: 116df1499c672f6d72c23894c4b9abe0133cbe855766175488384509845c5ec0
5
5
  SHA512:
6
- metadata.gz: 5742d45eb577916616ddba1bbe6b2b231ddb501a0795320aa4de58049a037f2f3b16101f4199093c068c4deebcb970f732a752ed050a2213926b422b3eaf5804
7
- data.tar.gz: a1df56de686279475cb65b2fb7b14afe49afe01b407f654eeafa48f3efb109c928d55289ce0e0aacab4e030590ea8241eab1d48d8bc950719704fe1a847ecdc2
6
+ metadata.gz: c1f5d964031547e6d9160d465a4b894f76aa7bbe3174c98dc7bb36964c52eddbb5a5d527c9bcfbd67f7aad93b5fe0869acc8ea0faa07fa97217f129bd537ad27
7
+ data.tar.gz: 03b84265b6fe59c1d2858fc12a8274fdb1301575b142f224ea6dd8d6f811c81b94dd9cab6918548e4c7249b57dd695b39bead9a5d0173af964edd334689b2a26
@@ -12,17 +12,12 @@ module Slacks
12
12
  end
13
13
 
14
14
  def reply(*messages)
15
- messages.flatten!
16
15
  return unless messages.any?
17
16
 
18
- first_message = messages.shift
19
- message_options = {}
20
- message_options = messages.shift if messages.length == 1 && messages[0].is_a?(Hash)
21
- slack.send_message(first_message, message_options.merge(channel: id))
22
-
23
- messages.each do |message|
24
- sleep message.length / slack.typing_speed
25
- slack.send_message(message, channel: id)
17
+ if messages.first.is_a?(Array)
18
+ reply_many(messages[0])
19
+ else
20
+ reply_one(*messages)
26
21
  end
27
22
  end
28
23
  alias :say :reply
@@ -61,6 +56,19 @@ module Slacks
61
56
  "##{name}"
62
57
  end
63
58
 
59
+ protected
60
+
61
+ def reply_one(message, options={})
62
+ slack.send_message(message, options.merge(channel: id))
63
+ end
64
+
65
+ def reply_many(messages)
66
+ messages.each_with_index.map do |message, i|
67
+ sleep message.length / slack.typing_speed if i > 0
68
+ slack.send_message(message, channel: id)
69
+ end
70
+ end
71
+
64
72
  private
65
73
  attr_reader :slack
66
74
  end
@@ -24,10 +24,8 @@ module Slacks
24
24
  @user_ids_dm_ids = {}
25
25
  @users_by_id = {}
26
26
  @user_id_by_name = {}
27
- @groups_by_id = {}
28
- @group_id_by_name = {}
29
- @channels_by_id = {}
30
- @channel_id_by_name = {}
27
+ @conversations_by_id = {}
28
+ @conversation_ids_by_name = {}
31
29
  end
32
30
 
33
31
 
@@ -41,11 +39,8 @@ module Slacks
41
39
  as_user: true, # post as the authenticated user (rather than as slackbot)
42
40
  link_names: 1} # find and link channel names and user names
43
41
  params.merge!(attachments: MultiJson.dump(attachments)) if attachments.any?
44
- params.merge!(options.select { |key, _| [:username, :as_user, :parse, :link_names,
45
- :unfurl_links, :unfurl_media, :icon_url, :icon_emoji].member?(key) })
46
- api("chat.postMessage", params)
47
- rescue Slacks::ResponseError
48
- $!.response
42
+ params.merge!(options.select { |key, _| SEND_MESSAGE_PARAMS.member?(key) })
43
+ api("chat.postMessage", **params)
49
44
  end
50
45
  alias :say :send_message
51
46
 
@@ -53,9 +48,7 @@ module Slacks
53
48
  params = {
54
49
  channel: to_channel_id(channel),
55
50
  timestamp: ts }
56
- api("reactions.get", params)
57
- rescue Slacks::ResponseError
58
- $!.response
51
+ api("reactions.get", **params)
59
52
  end
60
53
 
61
54
  def update_message(ts, message, options={})
@@ -70,34 +63,38 @@ module Slacks
70
63
  params.merge!(attachments: MultiJson.dump(attachments)) if attachments.any?
71
64
  params.merge!(options.select { |key, _| [:username, :as_user, :parse, :link_names,
72
65
  :unfurl_links, :unfurl_media, :icon_url, :icon_emoji].member?(key) })
73
- api("chat.update", params)
74
- rescue Slacks::ResponseError
75
- $!.response
66
+ api("chat.update", **params)
76
67
  end
77
68
 
78
69
  def add_reaction(emojis, message)
79
70
  Array(emojis).each do |emoji|
80
- api("reactions.add", {
71
+ api("reactions.add",
81
72
  name: emoji.gsub(/^:|:$/, ""),
82
73
  channel: message.channel.id,
83
- timestamp: message.timestamp })
74
+ timestamp: message.timestamp)
84
75
  end
85
- rescue Slacks::ResponseError
86
- $!.response
87
76
  end
88
77
 
78
+
79
+
89
80
  def typing_on(channel)
81
+ raise NotListeningError unless listening?
90
82
  websocket.write MultiJson.dump(type: "typing", channel: to_channel_id(channel))
91
83
  end
92
84
 
85
+ def ping
86
+ raise NotListeningError unless listening?
87
+ websocket.ping
88
+ end
89
+
90
+ def listening?
91
+ !websocket.nil?
92
+ end
93
+
93
94
 
94
95
 
95
96
  def listen!
96
97
  response = api("rtm.start")
97
- unless response["ok"]
98
- raise MigrationInProgress if response["error"] == "migration_in_progress"
99
- raise ResponseError.new(response, response["error"])
100
- end
101
98
  store_context!(response)
102
99
 
103
100
  @websocket = Slacks::Driver.new
@@ -117,21 +114,16 @@ module Slacks
117
114
  # one, we'll skill it.
118
115
  next
119
116
 
120
- when EVENT_GROUP_JOINED
121
- group = data["channel"]
122
- @groups_by_id[group["id"]] = group
123
- @group_id_by_name[group["name"]] = group["id"]
117
+ when EVENT_GROUP_JOINED, EVENT_CHANNEL_CREATED
118
+ conversation = data["channel"]
119
+ @conversations_by_id[conversation["id"]] = conversation
120
+ @conversation_ids_by_name[conversation["name"]] = conversation["id"]
124
121
 
125
122
  when EVENT_USER_JOINED
126
123
  user = data["user"]
127
124
  @users_by_id[user["id"]] = user
128
125
  @user_id_by_name[user["name"]] = user["id"]
129
126
 
130
- when EVENT_CHANNEL_CREATED
131
- channel = data["channel"]
132
- @channels_by_id[channel["id"]] = channel
133
- @channel_id_by_name[channel["name"]] = channel["id"]
134
-
135
127
  when EVENT_MESSAGE
136
128
  # Don't respond to things that this bot said
137
129
  next if data["user"] == bot.id
@@ -158,7 +150,18 @@ module Slacks
158
150
 
159
151
 
160
152
  def channels
161
- user_id_by_name.keys + group_id_by_name.keys + channel_id_by_name.keys
153
+ channels = user_id_by_name.keys + conversation_ids_by_name.keys
154
+ if channels.empty?
155
+ fetch_conversations!
156
+ fetch_users!
157
+ end
158
+ channels
159
+ end
160
+
161
+ def can_see?(channel)
162
+ to_channel_id(channel).present?
163
+ rescue ArgumentError
164
+ false
162
165
  end
163
166
 
164
167
 
@@ -172,13 +175,9 @@ module Slacks
172
175
  "id" => id,
173
176
  "is_im" => true,
174
177
  "name" => user.username }
175
- when /^G/
176
- Slacks::Channel.new(self, groups_by_id.fetch(id) do
177
- raise ArgumentError, "Unable to find a group with the ID #{id.inspect}"
178
- end)
179
178
  else
180
- Slacks::Channel.new(self, channels_by_id.fetch(id) do
181
- raise ArgumentError, "Unable to find a channel with the ID #{id.inspect}"
179
+ Slacks::Channel.new(self, conversations_by_id.fetch(id) do
180
+ raise ArgumentError, "Unable to find a conversation with the ID #{id.inspect}"
182
181
  end)
183
182
  end
184
183
  end
@@ -213,10 +212,8 @@ module Slacks
213
212
  attr_reader :user_ids_dm_ids,
214
213
  :users_by_id,
215
214
  :user_id_by_name,
216
- :groups_by_id,
217
- :group_id_by_name,
218
- :channels_by_id,
219
- :channel_id_by_name,
215
+ :conversations_by_id,
216
+ :conversation_ids_by_name,
220
217
  :websocket_url,
221
218
  :websocket
222
219
 
@@ -227,16 +224,8 @@ module Slacks
227
224
  @bot = BotUser.new(response.fetch("self"))
228
225
  @team = Team.new(response.fetch("team"))
229
226
 
230
- @channels_by_id = Hash[response.fetch("channels").map { |attrs| [attrs.fetch("id"), attrs] }]
231
- @channel_id_by_name = Hash[response.fetch("channels").map { |attrs| ["##{attrs.fetch("name")}", attrs.fetch("id")] }]
232
-
233
- @users_by_id = Hash[response.fetch("users").map { |attrs| [attrs.fetch("id"), attrs] }]
234
- @user_id_by_name = Hash[response.fetch("users").map { |attrs| ["@#{attrs.fetch("name")}", attrs.fetch("id")] }]
235
-
236
- @groups_by_id = Hash[response.fetch("groups").map { |attrs| [attrs.fetch("id"), attrs] }]
237
- @group_id_by_name = Hash[response.fetch("groups").map { |attrs| [attrs.fetch("name"), attrs.fetch("id")] }]
238
- rescue KeyError
239
- raise ResponseError.new(response, $!.message)
227
+ @conversations_by_id = Hash[response.fetch("channels").map { |attrs| [ attrs.fetch("id"), attrs ] }]
228
+ @conversation_ids_by_name = Hash[response.fetch("channels").map { |attrs| [ attrs["name"], attrs["id"] ] }]
240
229
  end
241
230
 
242
231
 
@@ -245,13 +234,9 @@ module Slacks
245
234
  return name.id if name.is_a?(Slacks::Channel)
246
235
  return name if name =~ /^[DGC]/ # this already looks like a channel id
247
236
  return get_dm_for_username(name) if name.start_with?("@")
248
- return to_group_id(name) unless name.start_with?("#")
249
237
 
250
- channel_id_by_name[name] || fetch_channels![name] || missing_channel!(name)
251
- end
252
-
253
- def to_group_id(name)
254
- group_id_by_name[name] || fetch_groups![name] || missing_group!(name)
238
+ name = name.gsub(/^#/, "") # Leading hashes are no longer a thing in the conversations API
239
+ conversation_ids_by_name[name] || fetch_conversations![name] || missing_conversation!(name)
255
240
  end
256
241
 
257
242
  def to_user_id(name)
@@ -264,40 +249,29 @@ module Slacks
264
249
 
265
250
  def get_dm_for_user_id(user_id)
266
251
  user_ids_dm_ids[user_id] ||= begin
267
- response = api("im.open", user: user_id)
268
- raise UnableToDirectMessageError.new(response, user_id) unless response["ok"]
252
+ response = api("conversations.open", user: user_id)
269
253
  response["channel"]["id"]
270
254
  end
271
255
  end
272
256
 
273
257
 
274
-
275
- def fetch_channels!
276
- response = api("channels.list")
277
- @channels_by_id = response["channels"].index_by { |attrs| attrs["id"] }
278
- @channel_id_by_name = Hash[response["channels"].map { |attrs| ["##{attrs["name"]}", attrs["id"]] }]
279
- end
280
-
281
- def fetch_groups!
282
- response = api("groups.list")
283
- @groups_by_id = response["groups"].index_by { |attrs| attrs["id"] }
284
- @group_id_by_name = Hash[response["groups"].map { |attrs| [attrs["name"], attrs["id"]] }]
258
+ def fetch_conversations!
259
+ conversations, ims = api("conversations.list")["channels"].partition { |attrs| attrs["is_channel"] || attrs["is_group"] }
260
+ user_ids_dm_ids.merge! Hash[ims.map { |attrs| attrs.values_at("user", "id") }]
261
+ @conversations_by_id = Hash[conversations.map { |attrs| [ attrs.fetch("id"), attrs ] }]
262
+ @conversation_ids_by_name = Hash[conversations.map { |attrs| [ attrs["name"], attrs["id"] ] }]
285
263
  end
286
264
 
287
265
  def fetch_users!
288
266
  response = api("users.list")
289
- @users_by_id = response["members"].index_by { |attrs| attrs["id"] }
267
+ @users_by_id = response["members"].each_with_object({}) { |attrs, hash| hash[attrs["id"]] = attrs }
290
268
  @user_id_by_name = Hash[response["members"].map { |attrs| ["@#{attrs["name"]}", attrs["id"]] }]
291
269
  end
292
270
 
293
271
 
294
272
 
295
- def missing_channel!(name)
296
- raise ArgumentError, "Couldn't find a channel named #{name}"
297
- end
298
-
299
- def missing_group!(name)
300
- raise ArgumentError, "Couldn't find a private group named #{name}"
273
+ def missing_conversation!(name)
274
+ raise ArgumentError, "Couldn't find a conversation named #{name}"
301
275
  end
302
276
 
303
277
  def missing_user!(name)
@@ -309,8 +283,7 @@ module Slacks
309
283
  def get_user_id_for_dm(dm)
310
284
  user_id = user_ids_dm_ids.key(dm)
311
285
  unless user_id
312
- response = api("im.list")
313
- user_ids_dm_ids.merge! Hash[response["ims"].map { |attrs| attrs.values_at("user", "id") }]
286
+ fetch_conversations!
314
287
  user_id = user_ids_dm_ids.key(dm)
315
288
  end
316
289
  raise ArgumentError, "Unable to find a user for the direct message ID #{dm.inspect}" unless user_id
@@ -319,9 +292,36 @@ module Slacks
319
292
 
320
293
 
321
294
 
322
- def api(command, options={})
323
- response = http.post(command, options.merge(token: token))
324
- MultiJson.load(response.body)
295
+ def api(command, page_limit: MAX_PAGES, **params)
296
+ params_with_token = params.merge(token: token)
297
+ response = api_post command, params_with_token
298
+ fetched_pages = 1
299
+ cursor = response.dig("response_metadata", "next_cursor")
300
+ while cursor && !cursor.empty? && fetched_pages < page_limit do
301
+ api_post(command, params_with_token.merge(cursor: cursor)).each do |key, value|
302
+ if value.is_a?(Array)
303
+ response[key].concat value
304
+ elsif value.is_a?(Hash)
305
+ response[key].merge! value
306
+ else
307
+ response[key] = value
308
+ end
309
+ end
310
+ fetched_pages += 1
311
+ cursor = response.dig("response_metadata", "next_cursor")
312
+ end
313
+ response
314
+ end
315
+
316
+ def api_post(command, params)
317
+ response = http.post(command, params)
318
+ response = MultiJson.load(response.body)
319
+ unless response["ok"]
320
+ response["error"].split(/,\s*/).each do |error_code|
321
+ raise ::Slacks::Response.fetch(error_code).new(command, params, response)
322
+ end
323
+ end
324
+ response
325
325
 
326
326
  rescue MultiJson::ParseError
327
327
  $!.additional_information[:response_body] = response.body
@@ -335,5 +335,22 @@ module Slacks
335
335
  end
336
336
  end
337
337
 
338
+
339
+
340
+ SEND_MESSAGE_PARAMS = %i{
341
+ username
342
+ as_user
343
+ parse
344
+ link_names
345
+ unfurl_links
346
+ unfurl_media
347
+ icon_url
348
+ icon_emoji
349
+ thread_ts
350
+ reply_broadcast
351
+ }.freeze
352
+
353
+ MAX_PAGES = 9001
354
+
338
355
  end
339
356
  end
data/lib/slacks/driver.rb CHANGED
@@ -70,6 +70,10 @@ module Slacks
70
70
  @driver.text(message)
71
71
  end
72
72
 
73
+ def ping
74
+ @driver.ping
75
+ end
76
+
73
77
  def connected?
74
78
  @connected || false
75
79
  end
data/lib/slacks/errors.rb CHANGED
@@ -1,19 +1,79 @@
1
1
  require "slacks/core_ext/exception"
2
2
 
3
3
  module Slacks
4
- class MigrationInProgress < RuntimeError
5
- def initialize
6
- super "Team is being migrated between servers. Try the request again in a few seconds."
4
+ module Response
5
+ class Error < RuntimeError
6
+ attr_reader :command, :params, :response
7
+
8
+ def initialize(command, params, response, message)
9
+ super message
10
+ @command = command
11
+ @params = params
12
+ @response = response
13
+ additional_information[:command] = command
14
+ additional_information[:params] = params
15
+ additional_information[:response] = response
16
+ end
7
17
  end
8
- end
9
18
 
10
- class ResponseError < RuntimeError
11
- attr_reader :response
19
+ class UnspecifiedError < ::Slacks::Response::Error
20
+ def initialize(command, params, response)
21
+ super command, params, response, "Request failed with #{response["error"].inspect}"
22
+ end
23
+ end
24
+
25
+ @_errors = {}
26
+
27
+ def self.fetch(error_code)
28
+ @_errors.fetch(error_code, ::Slacks::Response::UnspecifiedError)
29
+ end
30
+
31
+ {
32
+ "account_inactive" => "Authentication token is for a deleted user or team.",
33
+ "already_reacted" => "The specified item already has the user/reaction combination.",
34
+ "bad_timestamp" => "Value passed for timestamp was invalid.",
35
+ "cant_update_message" => "Authenticated user does not have permission to update this message.",
36
+ "channel_not_found" => "Value passed for channel was invalid.",
37
+ "edit_window_closed" => "The message cannot be edited due to the team message edit settings",
38
+ "fatal_error" => "",
39
+ "file_comment_not_found" => "File comment specified by file_comment does not exist.",
40
+ "file_not_found" => "File specified by file does not exist.",
41
+ "invalid_arg_name" => "The method was passed an argument whose name falls outside the bounds of common decency. This includes very long names and names with non-alphanumeric characters other than _. If you get this error, it is typically an indication that you have made a very malformed API call.",
42
+ "invalid_array_arg" => "The method was passed a PHP-style array argument (e.g. with a name like foo[7]). These are never valid with the Slack API.",
43
+ "invalid_auth" => "Invalid authentication token.",
44
+ "invalid_charset" => "The method was called via a POST request, but the charset specified in the Content-Type header was invalid. Valid charset names are: utf-8 iso-8859-1.",
45
+ "invalid_form_data" => "The method was called via a POST request with Content-Type application/x-www-form-urlencoded or multipart/form-data, but the form data was either missing or syntactically invalid.",
46
+ "invalid_name" => "Value passed for name was invalid.",
47
+ "invalid_post_type" => "The method was called via a POST request, but the specified Content-Type was invalid. Valid types are: application/json application/x-www-form-urlencoded multipart/form-data text/plain.",
48
+ "is_archived" => "Channel has been archived.",
49
+ "message_not_found" => "Message specified by channel and timestamp does not exist.",
50
+ "migration_in_progress" => "Team is being migrated between servers. See the team_migration_started event documentation for details.",
51
+ "missing_post_type" => "The method was called via a POST request and included a data payload, but the request did not include a Content-Type header.",
52
+ "msg_too_long" => "Message text is too long",
53
+ "no_item_specified" => "file, file_comment, or combination of channel and timestamp was not specified.",
54
+ "no_text" => "No message text provided",
55
+ "not_authed" => "No authentication token provided.",
56
+ "not_in_channel" => "Cannot post user messages to a channel they are not in.",
57
+ "rate_limited" => "Application has posted too many messages, read the Rate Limit documentation for more information",
58
+ "request_timeout" => "The method was called via a POST request, but the POST data was either missing or truncated.",
59
+ "too_many_attachments" => "Too many attachments were provided with this message. A maximum of 100 attachments are allowed on a message.",
60
+ "too_many_emoji" => "The limit for distinct reactions (i.e emoji) on the item has been reached.",
61
+ "too_many_reactions" => "The limit for reactions a person may add to the item has been reached."
62
+ }.each do |error_code, message|
63
+ class_name = error_code.gsub(/(?:^|_)([a-z]+)/) { $1.capitalize }
64
+ class_name = {
65
+ "MsgTooLong" => "MessageTooLong"
66
+ }.fetch(class_name, class_name)
67
+
68
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
69
+ class #{class_name} < ::Slacks::Response::Error
70
+ def initialize(command, params, response)
71
+ super command, params, response, "#{message}"
72
+ end
73
+ end
12
74
 
13
- def initialize(response, message)
14
- super message
15
- @response = response
16
- additional_information[:response] = response
75
+ @_errors["#{error_code}"] = ::Slacks::Response::#{class_name}
76
+ RUBY
17
77
  end
18
78
  end
19
79
 
@@ -24,21 +84,21 @@ module Slacks
24
84
  end
25
85
  end
26
86
 
27
- class AlreadyRespondedError < RuntimeError
28
- def initialize(message=nil)
29
- super message || "You have already replied to this Slash Command; you can only reply once"
30
- end
31
- end
32
-
33
87
  class NotInChannelError < RuntimeError
34
88
  def initialize(channel)
35
89
  super "The bot is not in the channel #{channel} and cannot reply"
36
90
  end
37
91
  end
38
92
 
39
- class UnableToDirectMessageError < ResponseError
40
- def initialize(response, user_id)
41
- super response, "Unable to direct message the user #{user_id.inspect}: #{response["error"]}"
93
+ class MissingTokenError < ArgumentError
94
+ def initialize
95
+ super "Unable to connect to Slack; a token has no"
96
+ end
97
+ end
98
+
99
+ class NotListeningError < ArgumentError
100
+ def initialize
101
+ super "Not connected to the RTM API; call `listen!` first"
42
102
  end
43
103
  end
44
104
  end
@@ -1,3 +1,3 @@
1
1
  module Slacks
2
- VERSION = "0.4.2"
2
+ VERSION = "0.6.0"
3
3
  end
data/slacks.gemspec CHANGED
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency "faraday-raise-errors"
26
26
  spec.add_dependency "concurrent-ruby"
27
27
 
28
- spec.add_development_dependency "bundler", "~> 1.10"
29
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "bundler"
29
+ spec.add_development_dependency "rake"
30
30
  spec.add_development_dependency "minitest", "~> 5.0"
31
31
  spec.add_development_dependency "pry"
32
32
  spec.add_development_dependency "minitest-reporters"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slacks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Lail
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-02 00:00:00.000000000 Z
11
+ date: 2021-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket-driver
@@ -84,30 +84,30 @@ dependencies:
84
84
  name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.10'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '1.10'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '10.0'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '10.0'
110
+ version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: minitest
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +164,7 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
- description:
167
+ description:
168
168
  email:
169
169
  - bob.lailfamily@gmail.com
170
170
  executables: []
@@ -196,7 +196,7 @@ homepage: https://github.com/houston/slacks
196
196
  licenses:
197
197
  - MIT
198
198
  metadata: {}
199
- post_install_message:
199
+ post_install_message:
200
200
  rdoc_options: []
201
201
  require_paths:
202
202
  - lib
@@ -211,9 +211,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
211
  - !ruby/object:Gem::Version
212
212
  version: '0'
213
213
  requirements: []
214
- rubyforge_project:
215
- rubygems_version: 2.2.2
216
- signing_key:
214
+ rubygems_version: 3.1.2
215
+ signing_key:
217
216
  specification_version: 4
218
217
  summary: A library for communicating via Slack
219
218
  test_files: []