slack_message 2.2.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +27 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +19 -0
- data/README.md +24 -24
- data/lib/slack_message/api.rb +25 -14
- data/lib/slack_message/dsl.rb +10 -10
- data/lib/slack_message/rspec.rb +12 -6
- data/lib/slack_message.rb +5 -2
- data/slack_message.gemspec +3 -1
- data/spec/slack_message_spec.rb +8 -11
- metadata +4 -4
- data/Gemfile.lock +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25b5670dec5c6c5d2ba870180aa636f192cce3c9d899936337f553bc18108b7d
|
4
|
+
data.tar.gz: 47bd6ff799803ce186cdd01057dfa47a852422c715a2d1c550a6d41fc484ba18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 022ca4f2ffb28a3976be37d7104fd59e3ed296d406bf90176b4745c36880a159306112eb444ca1a1151720ad1cdb6a08e2b2779ad1ff2151e837fbee925c5808
|
7
|
+
data.tar.gz: a3f3d4c889e7c4036c2063f0ef038c54f515779526c6d4a9b0858e5e812bf2ba6667e08298b63988a074f82066c8d7eb9494b3d02d6c4785ff291cbfc7824f75
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
strategy:
|
12
|
+
matrix:
|
13
|
+
os: [ubuntu-latest, macos-latest]
|
14
|
+
ruby-version: [3.0, 2.7, 2.6, 2.5]
|
15
|
+
runs-on: ${{ matrix.os }}
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby-version }}
|
23
|
+
bundler-cache: true
|
24
|
+
- name: Install dependencies
|
25
|
+
run: bundle install
|
26
|
+
- name: Run tests
|
27
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.3.1] - 2021-11-30
|
4
|
+
- Adjust that minimum version by changing some syntax to older styles. Given
|
5
|
+
support for ruby 2.4 ended almost 2 years ago, going to go ahead and leave
|
6
|
+
it behind.
|
7
|
+
- Remove lockfile from repo
|
8
|
+
|
9
|
+
## [2.3.0] - 2021-11-30
|
10
|
+
- Formally require minimum version of ruby. It wouldn't have worked anyway,
|
11
|
+
but worth actually specifying.
|
12
|
+
|
13
|
+
## [2.2.2] - 2021-11-30
|
14
|
+
- Add github workflow for automatic CI runs. Stolen from another project.
|
15
|
+
|
16
|
+
## [2.2.1] - 2021-11-20
|
17
|
+
- Trying to fetch user ID for a string that isn't email-like raises an error.
|
18
|
+
- In tests, fetching user IDs is mocked out to prevent network requests.
|
19
|
+
- Tightened up and clarified README.
|
20
|
+
- Some internal cleanup and restructuring of modules.
|
21
|
+
|
3
22
|
## [2.2.0] - 2021-11-20
|
4
23
|
- When sending text, it is now possible to mention users and have their user
|
5
24
|
IDs automatically converted using `<email@email.com>` within text nodes.
|
data/README.md
CHANGED
@@ -15,19 +15,21 @@ end
|
|
15
15
|
|
16
16
|
To install, just add `slack_message` to your bundle and you're ready to go.
|
17
17
|
|
18
|
-
Opinionated Stances
|
19
|
-
------------
|
18
|
+
#### Opinionated Stances
|
20
19
|
|
21
20
|
Slack's API has a lot of options available to you! But this gem takes some
|
22
|
-
opinionated stances
|
21
|
+
opinionated stances about usage to try to minimize the pain of integrating
|
22
|
+
with it. For example:
|
23
23
|
|
24
|
-
*
|
24
|
+
* SlackMessage has no dependencies. Your lockfile is enough of a mess already.
|
25
|
+
* The code to build a message should look a lot like the message itself. Code
|
26
|
+
that is simple to read and understand is a priority.
|
25
27
|
* Webhooks are passé. Only Slack Apps are supported now.
|
26
28
|
* Unless you request otherwise, text is always rendered using `mrkdwn`. If you
|
27
29
|
want plaintext, you'll need to ask for it. Same for the `emoji` flag.
|
28
30
|
* As many API semantics as possible are hidden. For instance, if you post to
|
29
|
-
something that looks like an email address, `slack_message` is going to try
|
30
|
-
look it up as an email address.
|
31
|
+
something that looks like an email address, `slack_message` is going to try
|
32
|
+
to look it up as an email address.
|
31
33
|
* A few little hacks on the block syntax, such as adding a `blank_line` (which
|
32
34
|
doesn't exist in the API), or leading spaces.
|
33
35
|
* Configuration is kept as simple as possible. But, as much heavy lifting as
|
@@ -173,9 +175,7 @@ It's just as easy to send messages directly to users. SlackMessage will look for
|
|
173
175
|
targets that are email-addressish, and look them up for you automatically:
|
174
176
|
|
175
177
|
```ruby
|
176
|
-
|
177
|
-
|
178
|
-
SlackMessage.post_to(user_email) do
|
178
|
+
SlackMessage.post_to('hello@joemastey.com') do
|
179
179
|
text "You specifically did it! :thumbsup:"
|
180
180
|
end
|
181
181
|
```
|
@@ -207,15 +207,13 @@ SlackMessage.post_to('#general') do
|
|
207
207
|
text "See more here: #{link('result', 'https://google.com')}"
|
208
208
|
end
|
209
209
|
|
210
|
-
text ":rocketship: hello@joemastey.com"
|
210
|
+
text ":rocketship: <hello@joemastey.com>"
|
211
211
|
|
212
212
|
context ":custom_slack_emoji: An example footer *with some markdown*."
|
213
213
|
end
|
214
214
|
```
|
215
215
|
|
216
216
|
SlackMessage will compose this into Block Kit syntax and send it on its way!
|
217
|
-
For now you'll need to read a bit of the source code to get the entire API. Sorry,
|
218
|
-
working on it.
|
219
217
|
|
220
218
|
If you've defined multiple profiles in configuration, you can specify which to
|
221
219
|
use for your message by specifying its name:
|
@@ -223,6 +221,7 @@ use for your message by specifying its name:
|
|
223
221
|
```ruby
|
224
222
|
SlackMessage.post_to('#general', as: :sidekiq_bot) do
|
225
223
|
text ":octagonal_sign: A job has failed permanently and needs to be rescued."
|
224
|
+
|
226
225
|
link_button "Sidekiq Dashboard", sidekiq_dashboard_url, style: :danger
|
227
226
|
end
|
228
227
|
```
|
@@ -261,16 +260,16 @@ SlackMessage.post_to('#general') do
|
|
261
260
|
end
|
262
261
|
```
|
263
262
|
|
264
|
-
Emails that are not wrapped in tags will be rendered as normal
|
265
|
-
|
266
|
-
|
263
|
+
Emails that are not wrapped in tags will be rendered as normal email addresses.
|
264
|
+
Additionally, Slack will automatically convert a number of channel names and
|
265
|
+
tags you're probably already used to:
|
267
266
|
|
268
267
|
```ruby
|
269
268
|
SlackMessage.post_to('#general') do
|
270
269
|
bot_name "CoffeeBot"
|
271
270
|
bot_icon ":coffee:"
|
272
271
|
|
273
|
-
text "@here
|
272
|
+
text "@here There's no coffee left! Let #general know when you fix it."
|
274
273
|
end
|
275
274
|
```
|
276
275
|
|
@@ -303,8 +302,8 @@ RSpec.configure do |config|
|
|
303
302
|
end
|
304
303
|
```
|
305
304
|
|
306
|
-
This will
|
307
|
-
some custom matchers:
|
305
|
+
This will prevent API calls from leaking in your tests, and will allow you
|
306
|
+
access to some custom matchers:
|
308
307
|
|
309
308
|
```ruby
|
310
309
|
expect {
|
@@ -340,12 +339,12 @@ of very complicated regexes.
|
|
340
339
|
What it Doesn't Do
|
341
340
|
------------
|
342
341
|
|
343
|
-
This gem is intended to stay
|
344
|
-
options and abilities, which
|
345
|
-
you want to add a feature, open an issue on Github first to see if it's
|
346
|
-
to be merged. This gem was built out of an existing need that _didn't_
|
347
|
-
|
348
|
-
expand the DSL to include more useful features.
|
342
|
+
This gem is intended to stay simple. Other Slack gems have lots of config
|
343
|
+
options and abilities, which makes them powerful, but makes them a pain to use.
|
344
|
+
If you want to add a feature, open an issue on Github first to see if it's
|
345
|
+
likely to be merged. This gem was built out of an existing need that _didn't_
|
346
|
+
include all of the block API, but I'd be inclined to merge features that
|
347
|
+
sustainably expand the DSL to include more useful features.
|
349
348
|
|
350
349
|
Some behaviors that are still planned but not yet added:
|
351
350
|
|
@@ -357,6 +356,7 @@ Some behaviors that are still planned but not yet added:
|
|
357
356
|
* multiple recipients
|
358
357
|
* more interesting return types for your message
|
359
358
|
* richer text formatting (for instance, `ul` is currently a hack)
|
359
|
+
* more and better organized testing capability
|
360
360
|
|
361
361
|
Contributing
|
362
362
|
------------
|
data/lib/slack_message/api.rb
CHANGED
@@ -2,18 +2,16 @@ require 'net/http'
|
|
2
2
|
require 'net/https'
|
3
3
|
require 'json'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
uri = URI("https://slack.com/api/users.lookupByEmail?email=#{email}")
|
8
|
-
request = Net::HTTP::Get.new(uri).tap do |req|
|
9
|
-
req['Authorization'] = "Bearer #{profile[:api_token]}"
|
10
|
-
req['Content-type'] = "application/json; charset=utf-8"
|
11
|
-
end
|
5
|
+
module SlackMessage::Api
|
6
|
+
extend self
|
12
7
|
|
13
|
-
|
14
|
-
|
8
|
+
def user_id_for(email, profile)
|
9
|
+
unless email =~ SlackMessage::EMAIL_PATTERN
|
10
|
+
raise ArgumentError, "Tried to find profile by invalid email address '#{email}'"
|
15
11
|
end
|
16
12
|
|
13
|
+
response = look_up_user_by_email(email, profile)
|
14
|
+
|
17
15
|
if response.code != "200"
|
18
16
|
raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
|
19
17
|
elsif response.body == ""
|
@@ -37,7 +35,7 @@ class SlackMessage::Api
|
|
37
35
|
payload["user"]["id"]
|
38
36
|
end
|
39
37
|
|
40
|
-
def
|
38
|
+
def post(payload, target, profile)
|
41
39
|
params = {
|
42
40
|
channel: target,
|
43
41
|
username: payload.custom_bot_name || profile[:name],
|
@@ -80,8 +78,23 @@ class SlackMessage::Api
|
|
80
78
|
response
|
81
79
|
end
|
82
80
|
|
83
|
-
|
84
|
-
|
81
|
+
private
|
82
|
+
|
83
|
+
# mostly for test harnesses
|
84
|
+
|
85
|
+
def look_up_user_by_email(email, profile)
|
86
|
+
uri = URI("https://slack.com/api/users.lookupByEmail?email=#{email}")
|
87
|
+
request = Net::HTTP::Get.new(uri).tap do |req|
|
88
|
+
req['Authorization'] = "Bearer #{profile[:api_token]}"
|
89
|
+
req['Content-type'] = "application/json; charset=utf-8"
|
90
|
+
end
|
91
|
+
|
92
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
93
|
+
http.request(request)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def post_message(profile, params)
|
85
98
|
uri = URI("https://slack.com/api/chat.postMessage")
|
86
99
|
request = Net::HTTP::Post.new(uri).tap do |req|
|
87
100
|
req['Authorization'] = "Bearer #{profile[:api_token]}"
|
@@ -93,6 +106,4 @@ class SlackMessage::Api
|
|
93
106
|
http.request(request)
|
94
107
|
end
|
95
108
|
end
|
96
|
-
|
97
|
-
private_class_method :post_message
|
98
109
|
end
|
data/lib/slack_message/dsl.rb
CHANGED
@@ -2,7 +2,7 @@ class SlackMessage::Dsl
|
|
2
2
|
attr_reader :body, :default_section, :custom_bot_name, :custom_bot_icon, :profile
|
3
3
|
attr_accessor :custom_notification
|
4
4
|
|
5
|
-
EMSPACE = " " # unicode emspace
|
5
|
+
EMSPACE = " " # unicode emspace, Slack won't compress this
|
6
6
|
|
7
7
|
def initialize(block, profile)
|
8
8
|
# Delegate missing methods to caller scope. Thanks 2008:
|
@@ -108,17 +108,17 @@ class SlackMessage::Dsl
|
|
108
108
|
@caller_self.send meth, *args, &blk
|
109
109
|
end
|
110
110
|
|
111
|
-
EMAIL_TAG_PATTERN = /<[^@ \t\r\n\<]+@[^@ \t\r\n]+\.[^@ \t\r\n]+>/
|
112
|
-
|
113
111
|
# replace emails w/ real user IDs
|
114
112
|
def enrich_text(text_body)
|
115
|
-
text_body.scan(EMAIL_TAG_PATTERN).each do |email_tag|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
113
|
+
text_body.scan(SlackMessage::EMAIL_TAG_PATTERN).each do |email_tag|
|
114
|
+
begin
|
115
|
+
raw_email = email_tag.gsub(/[><]/, '')
|
116
|
+
user_id = SlackMessage::Api::user_id_for(raw_email, profile)
|
117
|
+
|
118
|
+
text_body.gsub!(email_tag, "<@#{user_id}>") if user_id
|
119
|
+
rescue SlackMessage::ApiError => e
|
120
|
+
# swallow errors for not-found users
|
121
|
+
end
|
122
122
|
end
|
123
123
|
|
124
124
|
text_body
|
data/lib/slack_message/rspec.rb
CHANGED
@@ -30,7 +30,7 @@ module SlackMessage::RSpec
|
|
30
30
|
FauxResponse = Struct.new(:code, :body)
|
31
31
|
|
32
32
|
def self.included(_)
|
33
|
-
SlackMessage::Api.
|
33
|
+
SlackMessage::Api.undef_method(:post_message)
|
34
34
|
SlackMessage::Api.define_singleton_method(:post_message) do |profile, params|
|
35
35
|
@@listeners.each do |listener|
|
36
36
|
listener.record_call(params.merge(profile: profile))
|
@@ -53,6 +53,12 @@ module SlackMessage::RSpec
|
|
53
53
|
|
54
54
|
return FauxResponse.new('200', response.to_json)
|
55
55
|
end
|
56
|
+
|
57
|
+
SlackMessage::Api.undef_method(:look_up_user_by_email)
|
58
|
+
SlackMessage::Api.define_singleton_method(:look_up_user_by_email) do |email, profile|
|
59
|
+
response = {"ok"=>true, "user"=>{"id"=>"U5432CBA"}}
|
60
|
+
return FauxResponse.new('200', response.to_json)
|
61
|
+
end
|
56
62
|
end
|
57
63
|
|
58
64
|
# w/ channel
|
@@ -200,11 +206,11 @@ module SlackMessage::RSpec
|
|
200
206
|
SlackMessage::RSpec.unregister_expectation_listener(self)
|
201
207
|
|
202
208
|
@captured_calls
|
203
|
-
.
|
204
|
-
.
|
205
|
-
.
|
206
|
-
.
|
207
|
-
.
|
209
|
+
.select { |call| !@channel || call[:channel] == @channel }
|
210
|
+
.select { |call| !@profile || [call[:profile][:handle], call[:username]].include?(@profile) }
|
211
|
+
.select { |call| !@content || call.fetch(:blocks).to_s =~ @content }
|
212
|
+
.select { |call| !@icon || call.fetch(:icon_emoji, call.fetch(:icon_url, '')) == @icon }
|
213
|
+
.select { |call| !@icon_matching || call.fetch(:icon_emoji, call.fetch(:icon_url, '')) =~ @icon_matching }
|
208
214
|
.any?
|
209
215
|
end
|
210
216
|
|
data/lib/slack_message.rb
CHANGED
@@ -3,6 +3,9 @@ module SlackMessage
|
|
3
3
|
require 'slack_message/api'
|
4
4
|
require 'slack_message/configuration'
|
5
5
|
|
6
|
+
EMAIL_TAG_PATTERN = /<[^@ \t\r\n\<]+@[^@ \t\r\n]+\.[^@ \t\r\n]+>/
|
7
|
+
EMAIL_PATTERN = /^\S{1,}@\S{2,}\.\S{2,}$/
|
8
|
+
|
6
9
|
class ApiError < RuntimeError; end
|
7
10
|
|
8
11
|
def self.configuration
|
@@ -25,7 +28,7 @@ module SlackMessage
|
|
25
28
|
instance.instance_eval(&block)
|
26
29
|
end
|
27
30
|
|
28
|
-
target = Api::user_id_for(target, profile) if target =~
|
31
|
+
target = Api::user_id_for(target, profile) if target =~ EMAIL_PATTERN
|
29
32
|
|
30
33
|
Api.post(payload, target, profile)
|
31
34
|
end
|
@@ -41,7 +44,7 @@ module SlackMessage
|
|
41
44
|
end
|
42
45
|
|
43
46
|
target = profile[:default_channel]
|
44
|
-
target = Api::user_id_for(target, profile) if target =~
|
47
|
+
target = Api::user_id_for(target, profile) if target =~ EMAIL_PATTERN
|
45
48
|
|
46
49
|
Api.post(payload, target, profile)
|
47
50
|
end
|
data/slack_message.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'slack_message'
|
3
|
-
gem.version = "2.
|
3
|
+
gem.version = "2.3.1"
|
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'
|
@@ -18,6 +18,8 @@ Gem::Specification.new do |gem|
|
|
18
18
|
"source_code_uri" => "http://github.com/jmmastey/slack_message",
|
19
19
|
}
|
20
20
|
|
21
|
+
gem.required_ruby_version = '>= 2.5.0'
|
22
|
+
|
21
23
|
gem.add_development_dependency "rspec", "3.10.0"
|
22
24
|
gem.add_development_dependency "pry", "0.14.1"
|
23
25
|
gem.add_development_dependency "rb-readline", "0.5.5"
|
data/spec/slack_message_spec.rb
CHANGED
@@ -132,15 +132,6 @@ RSpec.describe SlackMessage do
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
-
it "can grab user IDs" do
|
136
|
-
allow(Net::HTTP).to receive(:start).and_return(
|
137
|
-
double(code: "200", body: '{ "user": { "id": "ABC123" }}')
|
138
|
-
)
|
139
|
-
|
140
|
-
result = SlackMessage::Api.user_id_for("hello@joemastey.com", profile)
|
141
|
-
expect(result).to eq("ABC123")
|
142
|
-
end
|
143
|
-
|
144
135
|
it "converts user IDs within text when tagged properly" do
|
145
136
|
allow(SlackMessage::Api).to receive(:user_id_for).and_return('ABC123')
|
146
137
|
|
@@ -151,13 +142,19 @@ RSpec.describe SlackMessage do
|
|
151
142
|
expect {
|
152
143
|
SlackMessage.post_to('#general') { text("Not Tagged: hello@joemastey.com ") }
|
153
144
|
}.to post_to_slack.with_content_matching(/hello@joemastey.com/)
|
145
|
+
end
|
154
146
|
|
155
|
-
|
156
|
-
allow(SlackMessage::Api).to receive(:user_id_for).and_raise(SlackMessage::ApiError)
|
147
|
+
it "is graceful about those failures" do
|
148
|
+
allow(SlackMessage::Api).to receive(:user_id_for).with('nuffin@nuffin.nuffin', any_args).and_raise(SlackMessage::ApiError)
|
149
|
+
allow(SlackMessage::Api).to receive(:user_id_for).with('hello@joemastey.com', any_args).and_return('ABC123')
|
157
150
|
|
158
151
|
expect {
|
159
152
|
SlackMessage.post_to('#general') { text("Not User: <nuffin@nuffin.nuffin>") }
|
160
153
|
}.to post_to_slack.with_content_matching(/\<nuffin@nuffin.nuffin\>/)
|
154
|
+
|
155
|
+
expect {
|
156
|
+
SlackMessage.post_to('#general') { text("Not User: <nuffin@nuffin.nuffin>, User: <hello@joemastey.com>") }
|
157
|
+
}.to post_to_slack.with_content_matching(/ABC123/)
|
161
158
|
end
|
162
159
|
end
|
163
160
|
end
|
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: 2.
|
4
|
+
version: 2.3.1
|
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-11-
|
11
|
+
date: 2021-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -58,12 +58,12 @@ executables: []
|
|
58
58
|
extensions: []
|
59
59
|
extra_rdoc_files: []
|
60
60
|
files:
|
61
|
+
- ".github/workflows/main.yml"
|
61
62
|
- ".gitignore"
|
62
63
|
- ".ruby-version"
|
63
64
|
- CHANGELOG.md
|
64
65
|
- CODE_OF_CONDUCT.md
|
65
66
|
- Gemfile
|
66
|
-
- Gemfile.lock
|
67
67
|
- MIT-LICENSE
|
68
68
|
- README.md
|
69
69
|
- lib/slack_message.rb
|
@@ -89,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
89
|
requirements:
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
92
|
+
version: 2.5.0
|
93
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
95
|
- - ">="
|
data/Gemfile.lock
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
slack_message (2.2.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
coderay (1.1.3)
|
10
|
-
diff-lcs (1.4.4)
|
11
|
-
method_source (1.0.0)
|
12
|
-
pry (0.14.1)
|
13
|
-
coderay (~> 1.1)
|
14
|
-
method_source (~> 1.0)
|
15
|
-
rb-readline (0.5.5)
|
16
|
-
rspec (3.10.0)
|
17
|
-
rspec-core (~> 3.10.0)
|
18
|
-
rspec-expectations (~> 3.10.0)
|
19
|
-
rspec-mocks (~> 3.10.0)
|
20
|
-
rspec-core (3.10.1)
|
21
|
-
rspec-support (~> 3.10.0)
|
22
|
-
rspec-expectations (3.10.1)
|
23
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
-
rspec-support (~> 3.10.0)
|
25
|
-
rspec-mocks (3.10.2)
|
26
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
-
rspec-support (~> 3.10.0)
|
28
|
-
rspec-support (3.10.2)
|
29
|
-
|
30
|
-
PLATFORMS
|
31
|
-
ruby
|
32
|
-
|
33
|
-
DEPENDENCIES
|
34
|
-
pry (= 0.14.1)
|
35
|
-
rb-readline (= 0.5.5)
|
36
|
-
rspec (= 3.10.0)
|
37
|
-
slack_message!
|
38
|
-
|
39
|
-
BUNDLED WITH
|
40
|
-
2.1.4
|