slack-messenger 2.3.3

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.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/lib/slack-messenger.rb +59 -0
  3. data/lib/slack-messenger/config.rb +43 -0
  4. data/lib/slack-messenger/payload_middleware.rb +24 -0
  5. data/lib/slack-messenger/payload_middleware/at.rb +36 -0
  6. data/lib/slack-messenger/payload_middleware/base.rb +34 -0
  7. data/lib/slack-messenger/payload_middleware/channels.rb +21 -0
  8. data/lib/slack-messenger/payload_middleware/format_attachments.rb +44 -0
  9. data/lib/slack-messenger/payload_middleware/format_message.rb +20 -0
  10. data/lib/slack-messenger/payload_middleware/stack.rb +50 -0
  11. data/lib/slack-messenger/util/escape.rb +16 -0
  12. data/lib/slack-messenger/util/http_client.rb +64 -0
  13. data/lib/slack-messenger/util/link_formatter.rb +81 -0
  14. data/lib/slack-messenger/version.rb +7 -0
  15. data/spec/end_to_end_spec.rb +95 -0
  16. data/spec/integration/ping_integration_test.rb +16 -0
  17. data/spec/lib/slack-messenger/config_spec.rb +71 -0
  18. data/spec/lib/slack-messenger/payload_middleware/at_spec.rb +25 -0
  19. data/spec/lib/slack-messenger/payload_middleware/base_spec.rb +76 -0
  20. data/spec/lib/slack-messenger/payload_middleware/channels_spec.rb +20 -0
  21. data/spec/lib/slack-messenger/payload_middleware/format_attachments_spec.rb +48 -0
  22. data/spec/lib/slack-messenger/payload_middleware/format_message_spec.rb +27 -0
  23. data/spec/lib/slack-messenger/payload_middleware/stack_spec.rb +119 -0
  24. data/spec/lib/slack-messenger/payload_middleware_spec.rb +33 -0
  25. data/spec/lib/slack-messenger/util/http_client_spec.rb +55 -0
  26. data/spec/lib/slack-messenger/util/link_formatter_spec.rb +155 -0
  27. data/spec/lib/slack-messenger_spec.rb +98 -0
  28. data/spec/spec_helper.rb +28 -0
  29. metadata +84 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slack
4
+ class Messenger
5
+ VERSION = "2.3.3".freeze # rubocop:disable Style/RedundantFreeze
6
+ end
7
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require "spec_helper"
5
+
6
+ RSpec.describe Slack::Messenger do
7
+ {
8
+ { text: "hello" } =>
9
+ { payload: { text: "hello" } },
10
+
11
+ { text: "[hello](http://example.com/world)" } =>
12
+ { payload: { text: "<http://example.com/world|hello>" } },
13
+
14
+ { text: '<a href="http://example.com">example</a>' } =>
15
+ { payload: { text: "<http://example.com|example>" } },
16
+
17
+ { text: "hello/こんにちは from messenger test" } =>
18
+ { payload: { text: "hello/こんにちは from messenger test" } },
19
+
20
+ { text: "Hello World, enjoy [](http://example.com)." } =>
21
+ { payload: { text: "Hello World, enjoy <http://example.com>." } },
22
+
23
+ { text: "Hello World, enjoy [this](http://example.com)[this2](http://example2.com)" } =>
24
+ { payload: { text: "Hello World, enjoy <http://example.com|this><http://example2.com|this2>" } },
25
+
26
+ { text: "[John](mailto:john@example.com)" } =>
27
+ { payload: { text: "<mailto:john@example.com|John>" } },
28
+
29
+ { text: '<a href="mailto:john@example.com">John</a>' } =>
30
+ { payload: { text: "<mailto:john@example.com|John>" } },
31
+
32
+ { text: "hello", channel: "hodor" } =>
33
+ { payload: { text: "hello", channel: "hodor" } },
34
+
35
+ { text: nil, attachments: [{ text: "attachment message" }] } =>
36
+ { payload: { text: nil, attachments: [{ text: "attachment message" }] } },
37
+
38
+ { text: "the message", channel: "foo", attachments: [{ color: "#000",
39
+ text: "attachment message",
40
+ fallback: "fallback message" }] } =>
41
+ { payload: { text: "the message",
42
+ channel: "foo",
43
+ attachments: [{ color: "#000",
44
+ text: "attachment message",
45
+ fallback: "fallback message" }] } },
46
+
47
+ { attachments: [{ color: "#000",
48
+ text: "attachment message",
49
+ fallback: "fallback message" }] } =>
50
+ { payload: { attachments: [{ color: "#000",
51
+ text: "attachment message",
52
+ fallback: "fallback message" }] } },
53
+
54
+ { attachments: { color: "#000",
55
+ text: "attachment message [hodor](http://winterfell.com)",
56
+ fallback: "fallback message" } } =>
57
+ { payload: { attachments: [{ color: "#000",
58
+ text: "attachment message <http://winterfell.com|hodor>",
59
+ fallback: "fallback message" }] } },
60
+
61
+ { attachments: { color: "#000",
62
+ text: nil,
63
+ fallback: "fallback message" } } =>
64
+ { payload: { attachments: [{ color: "#000",
65
+ text: nil,
66
+ fallback: "fallback message" }] } },
67
+
68
+ { text: "hello", http_options: { timeout: 5 } } =>
69
+ { http_options: { timeout: 5 }, payload: { text: "hello" } }
70
+ }.each do |args, payload|
71
+ it "sends correct payload for #post(#{args})" do
72
+ http_client = class_double("Slack::Messenger::Util::HTTPClient", post: nil)
73
+ messenger = Slack::Messenger.new "http://example.com", http_client: http_client
74
+ payload[:payload] = payload[:payload].to_json
75
+
76
+ expect(http_client).to receive(:post)
77
+ .with(URI.parse("http://example.com"), payload)
78
+
79
+ messenger.post(args)
80
+ end
81
+ end
82
+
83
+ it "applies options given to middleware" do
84
+ client = class_double("Slack::Messenger::Util::HTTPClient", post: nil)
85
+ messenger = Slack::Messenger.new "http://example.com" do
86
+ http_client client
87
+ middleware format_message: { formats: [] }
88
+ end
89
+
90
+ expect(client).to receive(:post)
91
+ .with(URI.parse("http://example.com"), payload: { text: "Hello [world](http://example.com)!" }.to_json)
92
+
93
+ messenger.post text: "Hello [world](http://example.com)!"
94
+ end
95
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require_relative "../../lib/slack-messenger"
5
+
6
+ ruby = if defined?(JRUBY_VERSION)
7
+ "jruby #{JRUBY_VERSION}"
8
+ else
9
+ "ruby #{RUBY_VERSION}"
10
+ end
11
+ puts "testing with #{ruby}"
12
+
13
+ messenger = Slack::Messenger.new ENV["SLACK_WEBHOOK_URL"], username: "messenger"
14
+ messenger.ping "hello", channel: ["#general", "#random"]
15
+ messenger.ping "hello/こんにちは from messenger test script on #{ruby}\225"
16
+ messenger.ping attachments: [{ color: "#1BF5AF", fallback: "fallback", text: "attachment" }]
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::Config do
4
+ describe "#http_client" do
5
+ it "is Util::HTTPClient if not set" do
6
+ subject = described_class.new
7
+ expect(subject.http_client).to eq Slack::Messenger::Util::HTTPClient
8
+ end
9
+
10
+ it "sets a new client class if given one" do
11
+ new_client = class_double("Slack::Messenger::Util::HTTPClient", post: nil)
12
+ subject = described_class.new
13
+ subject.http_client new_client
14
+ expect(subject.http_client).to eq new_client
15
+ end
16
+
17
+ it "raises an ArgumentError if given class does not respond to ::post" do
18
+ subject = described_class.new
19
+ expect do
20
+ subject.http_client :nope
21
+ end.to raise_error ArgumentError
22
+ end
23
+ end
24
+
25
+ describe "#defaults" do
26
+ it "is an empty hash by default" do
27
+ subject = described_class.new
28
+ expect(subject.defaults).to eq({})
29
+ end
30
+
31
+ it "sets a hash to default if given" do
32
+ subject = described_class.new
33
+ subject.defaults foo: :bar
34
+ expect(subject.defaults).to eq foo: :bar
35
+ end
36
+
37
+ it "raises ArgumentError if not given a hash" do
38
+ subject = described_class.new
39
+ expect do
40
+ subject.defaults :nope
41
+ end.to raise_error ArgumentError
42
+ end
43
+ end
44
+
45
+ describe "#middleware" do
46
+ it "is [:format_message, :format_attachments, :at] if not set" do
47
+ subject = described_class.new
48
+
49
+ expect(subject.middleware).to eq %i[format_message format_attachments at channels]
50
+ end
51
+
52
+ it "takes an array or a splat of args" do
53
+ subject = described_class.new
54
+
55
+ subject.middleware :layer, :two
56
+ expect(subject.middleware).to eq %i[layer two]
57
+
58
+ subject.middleware %i[one layer]
59
+ expect(subject.middleware).to eq %i[one layer]
60
+ end
61
+
62
+ it "allows passing options to middleware stack" do
63
+ subject = described_class.new
64
+ subject.middleware one: { opts: :for_one },
65
+ two: { opts: :for_two }
66
+
67
+ expect(subject.middleware).to eq one: { opts: :for_one },
68
+ two: { opts: :for_two }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::At do
4
+ it "can handle array at" do
5
+ subject = described_class.new(:messenger)
6
+ payload = { text: "hello", at: %i[john ken here] }
7
+
8
+ expect(subject.call(payload)).to eq text: "<@john> <@ken> <!here> hello"
9
+ end
10
+
11
+ it "can handle single at option" do
12
+ subject = described_class.new(:messenger)
13
+ payload = { text: "hello", at: :alice }
14
+
15
+ expect(subject.call(payload)).to eq text: "<@alice> hello"
16
+ end
17
+
18
+ it "generates :text in payload if given :at & no :text" do
19
+ subject = described_class.new(:messenger)
20
+ input_payload = { at: [:here], attachments: [{ text: "hello" }] }
21
+ output_payload = { text: "<!here> ", attachments: [{ text: "hello" }] }
22
+
23
+ expect(subject.call(input_payload)).to eq output_payload
24
+ end
25
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::Base do
4
+ before(:each) do
5
+ @registry_backup = Slack::Messenger::PayloadMiddleware.registry.dup
6
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
7
+ end
8
+
9
+ after(:each) do
10
+ # cleanup middleware registry
11
+ Slack::Messenger::PayloadMiddleware.registry
12
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
13
+
14
+ # cleanup object constants
15
+ Object.send(:remove_const, :Subject) if Object.constants.include?(:Subject)
16
+ Slack::Messenger::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
17
+ end
18
+
19
+ describe "::middleware_name" do
20
+ it "registers class w/ given name" do
21
+ class Subject < Slack::Messenger::PayloadMiddleware::Base
22
+ end
23
+
24
+ expect(Slack::Messenger::PayloadMiddleware)
25
+ .to receive(:register).with(Subject, :subject)
26
+
27
+ class Subject
28
+ middleware_name :subject
29
+ end
30
+ end
31
+
32
+ it "uses symbolized name to register" do
33
+ class Subject < Slack::Messenger::PayloadMiddleware::Base
34
+ end
35
+
36
+ expect(Slack::Messenger::PayloadMiddleware)
37
+ .to receive(:register).with(Subject, :subject)
38
+
39
+ class Subject
40
+ middleware_name "subject"
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "::options" do
46
+ it "allows setting default options for a middleware" do
47
+ class Subject < Slack::Messenger::PayloadMiddleware::Base
48
+ options foo: :bar
49
+ end
50
+
51
+ subject = Subject.new(:messenger)
52
+ expect(subject.options).to eq foo: :bar
53
+
54
+ subject = Subject.new(:messenger, foo: :baz)
55
+ expect(subject.options).to eq foo: :baz
56
+ end
57
+ end
58
+
59
+ describe "#initialize" do
60
+ it "sets given messenger as messenger" do
61
+ expect(described_class.new(:messenger).messenger).to eq :messenger
62
+ end
63
+
64
+ it "sets given options as opts" do
65
+ expect(described_class.new(:messenger, opts: :options).options).to eq opts: :options
66
+ end
67
+ end
68
+
69
+ describe "#call" do
70
+ it "raises NoMethodError (expects subclass to define)" do
71
+ expect do
72
+ described_class.new(:messenger).call
73
+ end.to raise_exception NoMethodError
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::Channels do
4
+ it "leaves string channels alone" do
5
+ subject = described_class.new(:messenger)
6
+ payload = { text: "hello", channel: "hodor" }
7
+
8
+ expect(subject.call(payload)).to eq text: "hello", channel: "hodor"
9
+ end
10
+
11
+ it "splits payload into multiple if given an array of channels" do
12
+ subject = described_class.new(:messenger)
13
+ payload = { text: "hello", channel: %w[foo hodor] }
14
+
15
+ expect(subject.call(payload)).to eq [
16
+ { text: "hello", channel: "foo" },
17
+ { text: "hello", channel: "hodor" }
18
+ ]
19
+ end
20
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::FormatAttachments do
4
+ it "passes the text of attachments through linkformatter with options[:formats]" do
5
+ subject = described_class.new(:messenger, formats: [:html])
6
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
7
+ .with("hello", formats: [:html])
8
+ subject.call(attachments: [{ text: "hello" }])
9
+ end
10
+
11
+ it "searches through string or symbol keys" do
12
+ subject = described_class.new(:messenger)
13
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
14
+ .with("hello", formats: %i[html markdown])
15
+ subject.call("attachments" => [{ "text" => "hello" }])
16
+
17
+ subject = described_class.new(:messenger)
18
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
19
+ .with("hello", formats: %i[html markdown])
20
+ subject.call(attachments: [{ text: "hello" }])
21
+ end
22
+
23
+ it "can handle a single attachment" do
24
+ subject = described_class.new(:messenger)
25
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
26
+ .with("hello", formats: %i[html markdown])
27
+ subject.call(attachments: { text: "hello" })
28
+ end
29
+
30
+ it "wraps attachment into array if given as a single hash" do
31
+ params = {
32
+ attachments: { text: "hello" }
33
+ }
34
+ payload = {
35
+ attachments: [{ text: "hello" }]
36
+ }
37
+ subject = described_class.new(:messenger)
38
+
39
+ expect(subject.call(params)).to eq payload
40
+ end
41
+
42
+ it "returns the payload unmodified if not :attachments key" do
43
+ payload = { foo: :bar }
44
+ subject = described_class.new(:messenger)
45
+
46
+ expect(subject.call(payload)).to eq payload
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::FormatMessage do
4
+ it "passes the text through linkformatter with options[:formats]" do
5
+ subject = described_class.new(:messenger, formats: [:html])
6
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
7
+ .with("hello", formats: [:html])
8
+ subject.call(text: "hello")
9
+
10
+ subject = described_class.new(:messenger)
11
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
12
+ .with("hello", formats: %i[html markdown])
13
+ subject.call(text: "hello")
14
+
15
+ subject = described_class.new(:messenger, formats: [:markdown])
16
+ expect(Slack::Messenger::Util::LinkFormatter).to receive(:format)
17
+ .with("hello", formats: [:markdown])
18
+ subject.call(text: "hello")
19
+ end
20
+
21
+ it "returns the payload unmodified if not :text key" do
22
+ payload = { foo: :bar }
23
+ subject = described_class.new(:messenger)
24
+
25
+ expect(subject.call(payload)).to eq payload
26
+ end
27
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Slack::Messenger::PayloadMiddleware::Stack do
4
+ let(:return_one) do
5
+ double(call: 1)
6
+ end
7
+
8
+ let(:return_one_twice) do
9
+ double(call: [1, 1])
10
+ end
11
+
12
+ let(:return_two) do
13
+ double(call: 2)
14
+ end
15
+
16
+ let(:return_three) do
17
+ double(call: 3)
18
+ end
19
+
20
+ before(:each) do
21
+ # setup our middleware in the registry
22
+ @registry_backup = Slack::Messenger::PayloadMiddleware.registry.dup
23
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
24
+
25
+ Slack::Messenger::PayloadMiddleware.register return_one, :return_one
26
+ Slack::Messenger::PayloadMiddleware.register return_one_twice, :return_one_twice
27
+ Slack::Messenger::PayloadMiddleware.register return_two, :return_two
28
+ Slack::Messenger::PayloadMiddleware.register return_three, :return_three
29
+ end
30
+
31
+ after(:each) do
32
+ # cleanup middleware registry
33
+ Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry)
34
+ Slack::Messenger::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
35
+ end
36
+
37
+ describe "::initialize" do
38
+ it "sets messenger to given messenger" do
39
+ expect(described_class.new(:messenger).messenger).to eq :messenger
40
+ end
41
+
42
+ it "has empty stack" do
43
+ expect(described_class.new(:messenger).stack).to match_array []
44
+ end
45
+ end
46
+
47
+ describe "#set" do
48
+ it "initializes each middleware w/ the messenger instance" do
49
+ expect(return_one).to receive(:new).with(:messenger)
50
+ expect(return_two).to receive(:new).with(:messenger)
51
+
52
+ described_class.new(:messenger).set(:return_one, :return_two)
53
+ end
54
+
55
+ it "creates the stack in an array" do
56
+ allow(return_one).to receive(:new).and_return(return_one)
57
+ allow(return_two).to receive(:new).and_return(return_two)
58
+
59
+ subject = described_class.new(:messenger)
60
+ subject.set(:return_one, :return_two)
61
+
62
+ expect(subject.stack).to be_a Array
63
+ expect(subject.stack.first.call).to eq 1
64
+ expect(subject.stack.last.call).to eq 2
65
+ end
66
+
67
+ it "creates a stack from hashes passing them as opts" do
68
+ expect(return_one).to receive(:new).with(:messenger, opts: :for_one)
69
+ expect(return_two).to receive(:new).with(:messenger, opts: :for_two)
70
+
71
+ subject = described_class.new(:messenger)
72
+ subject.set return_one: { opts: :for_one },
73
+ return_two: { opts: :for_two }
74
+ end
75
+
76
+ it "raises if a middleware is missing" do
77
+ expect do
78
+ described_class.new(:messenger).set(:missing)
79
+ end.to raise_exception KeyError
80
+ end
81
+ end
82
+
83
+ describe "#call" do
84
+ it "calls the middleware in order, passing return of each to the next" do
85
+ allow(return_one).to receive(:new).and_return(return_one)
86
+ allow(return_two).to receive(:new).and_return(return_two)
87
+ allow(return_three).to receive(:new).and_return(return_three)
88
+
89
+ subject = described_class.new(:messenger)
90
+ subject.set(:return_one, :return_three, :return_two)
91
+
92
+ expect(return_one).to receive(:call).with(5)
93
+ expect(return_three).to receive(:call).with(1)
94
+ expect(return_two).to receive(:call).with(3)
95
+
96
+ expect(subject.call(5)).to eq [2]
97
+ end
98
+
99
+ it "allows any middleware to return an array but other's don't need special behavior" do
100
+ allow(return_one_twice).to receive(:new).and_return(return_one_twice)
101
+ allow(return_two).to receive(:new).and_return(return_two)
102
+
103
+ subject = described_class.new(:messenger)
104
+ subject.set(:return_one_twice, :return_two)
105
+
106
+ expect(subject.call(5)).to eq [2, 2]
107
+ end
108
+
109
+ it "handles multiple middleware splitting payload" do
110
+ allow(return_one_twice).to receive(:new).and_return(return_one_twice)
111
+ allow(return_two).to receive(:new).and_return(return_two)
112
+
113
+ subject = described_class.new(:messenger)
114
+ subject.set(:return_one_twice, :return_one_twice, :return_two)
115
+
116
+ expect(subject.call(5)).to eq [2, 2, 2, 2]
117
+ end
118
+ end
119
+ end