slack-messenger-2.3.3/0000755000175000017500000000000013637141201014402 5ustar abhinavabhinavslack-messenger-2.3.3/slack-messenger.gemspec0000644000175000017500000000625013637141201021035 0ustar abhinavabhinav######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: slack-messenger 2.3.3 ruby lib Gem::Specification.new do |s| s.name = "slack-messenger".freeze s.version = "2.3.3" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Steven Sloan".freeze] s.date = "2020-02-09" s.description = " A slim ruby wrapper for posting to slack webhooks ".freeze s.email = ["stevenosloan@gmail.com".freeze] s.files = ["lib/slack-messenger.rb".freeze, "lib/slack-messenger/config.rb".freeze, "lib/slack-messenger/payload_middleware.rb".freeze, "lib/slack-messenger/payload_middleware/at.rb".freeze, "lib/slack-messenger/payload_middleware/base.rb".freeze, "lib/slack-messenger/payload_middleware/channels.rb".freeze, "lib/slack-messenger/payload_middleware/format_attachments.rb".freeze, "lib/slack-messenger/payload_middleware/format_message.rb".freeze, "lib/slack-messenger/payload_middleware/stack.rb".freeze, "lib/slack-messenger/util/escape.rb".freeze, "lib/slack-messenger/util/http_client.rb".freeze, "lib/slack-messenger/util/link_formatter.rb".freeze, "lib/slack-messenger/version.rb".freeze, "spec/end_to_end_spec.rb".freeze, "spec/integration/ping_integration_test.rb".freeze, "spec/lib/slack-messenger/config_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/at_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/base_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/channels_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/format_attachments_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/format_message_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/stack_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware_spec.rb".freeze, "spec/lib/slack-messenger/util/http_client_spec.rb".freeze, "spec/lib/slack-messenger/util/link_formatter_spec.rb".freeze, "spec/lib/slack-messenger_spec.rb".freeze, "spec/spec_helper.rb".freeze] s.homepage = "http://github.com/stevenosloan/slack-messenger".freeze s.licenses = ["MIT".freeze] s.rubygems_version = "3.1.2".freeze s.summary = "A slim ruby wrapper for posting to slack webhooks".freeze s.test_files = ["spec/end_to_end_spec.rb".freeze, "spec/integration/ping_integration_test.rb".freeze, "spec/lib/slack-messenger/config_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/at_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/base_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/channels_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/format_attachments_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/format_message_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware/stack_spec.rb".freeze, "spec/lib/slack-messenger/payload_middleware_spec.rb".freeze, "spec/lib/slack-messenger/util/http_client_spec.rb".freeze, "spec/lib/slack-messenger/util/link_formatter_spec.rb".freeze, "spec/lib/slack-messenger_spec.rb".freeze, "spec/spec_helper.rb".freeze] end slack-messenger-2.3.3/lib/0000755000175000017500000000000013637141201015150 5ustar abhinavabhinavslack-messenger-2.3.3/lib/slack-messenger/0000755000175000017500000000000013637141201020233 5ustar abhinavabhinavslack-messenger-2.3.3/lib/slack-messenger/config.rb0000644000175000017500000000176313637141201022034 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class Config def initialize @http_client = Util::HTTPClient @defaults = {} @middleware = %i[ format_message format_attachments at channels ] end def http_client client=nil return @http_client if client.nil? raise ArgumentError, "the http client must respond to ::post" unless client.respond_to?(:post) @http_client = client end def defaults new_defaults=nil return @defaults if new_defaults.nil? raise ArgumentError, "the defaults must be a Hash" unless new_defaults.is_a?(Hash) @defaults = new_defaults end def middleware *args return @middleware if args.empty? @middleware = if args.length == 1 && args.first.is_a?(Array) || args.first.is_a?(Hash) args.first else args end end end end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware/0000755000175000017500000000000013637141201024061 5ustar abhinavabhinavslack-messenger-2.3.3/lib/slack-messenger/payload_middleware/channels.rb0000644000175000017500000000067113637141201026205 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class Channels < Base middleware_name :channels def call payload={} return payload unless payload[:channel].respond_to?(:to_ary) payload[:channel].to_ary.map do |channel| pld = payload.dup pld[:channel] = channel pld end end end end end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware/format_message.rb0000644000175000017500000000064513637141201027407 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class FormatMessage < Base middleware_name :format_message options formats: %i[html markdown] def call payload={} return payload unless payload[:text] payload[:text] = Util::LinkFormatter.format(payload[:text], options) payload end end end end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware/at.rb0000644000175000017500000000132113637141201025007 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class At < Base middleware_name :at options at: [] def call payload={} return payload unless payload[:at] payload[:text] = "#{format_ats(payload.delete(:at))}#{payload[:text]}" payload end private def format_ats ats Array(ats).map { |at| "<#{at_cmd_char(at)}#{at}> " } .join("") end def at_cmd_char at case at when :here, :channel, :everyone, :group "!" else "@" end end end end end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware/stack.rb0000644000175000017500000000211313637141201025510 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class Stack attr_reader :messenger, :stack def initialize messenger @messenger = messenger @stack = [] end def set *middlewares middlewares = if middlewares.length == 1 && middlewares.first.is_a?(Hash) middlewares.first else middlewares.flatten end @stack = middlewares.map do |key, opts| PayloadMiddleware.registry.fetch(key).new(*[messenger, opts].compact) end end def call payload={} result = stack.inject payload do |pld, middleware| as_array(pld).flat_map do |p| middleware.call(p) end end as_array(result) end private def as_array args if args.respond_to?(:to_ary) args.to_ary else [args] end end end end end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware/base.rb0000644000175000017500000000136113637141201025321 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class Base class << self def middleware_name name PayloadMiddleware.register self, name.to_sym end def options default_opts @default_opts = default_opts end def default_opts @default_opts ||= {} end end attr_reader :messenger, :options def initialize messenger, opts={} @messenger = messenger @options = self.class.default_opts.merge opts end def call _payload={} raise NoMethodError, "method `call` not defined for class #{self.class}" end end end end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware/format_attachments.rb0000644000175000017500000000207613637141201030276 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class FormatAttachments < Base middleware_name :format_attachments options formats: %i[html markdown] def call payload={} payload = payload.dup attachments = payload.delete(:attachments) attachments ||= payload.delete("attachments") attachments = wrap_array(attachments).map do |attachment| ["text", :text].each do |key| if attachment.key?(key) attachment[key] = Util::LinkFormatter.format(attachment[key], options) end end attachment end payload[:attachments] = attachments if attachments && !attachments.empty? payload end private def wrap_array object if object.nil? [] elsif object.respond_to?(:to_ary) object.to_ary || [object] else [object] end end end end end end slack-messenger-2.3.3/lib/slack-messenger/util/0000755000175000017500000000000013637141201021210 5ustar abhinavabhinavslack-messenger-2.3.3/lib/slack-messenger/util/http_client.rb0000644000175000017500000000313513637141201024054 0ustar abhinavabhinav# frozen_string_literal: true require "net/http" module Slack class Messenger class APIError < StandardError; end module Util class HTTPClient class << self def post uri, params HTTPClient.new(uri, params).call end end attr_reader :uri, :params, :http_options def initialize uri, params @uri = uri @http_options = params.delete(:http_options) || {} @params = params end # rubocop:disable Layout/IndentHeredoc def call http_obj.request(request_obj).tap do |response| unless response.is_a?(Net::HTTPSuccess) raise Slack::Messenger::APIError, <<-MSG The slack API returned an error: #{response.body} (HTTP Code #{response.code}) Check the "Handling Errors" section on https://api.slack.com/incoming-webhooks for more information MSG end end end # rubocop:enable Layout/IndentHeredoc private def request_obj req = Net::HTTP::Post.new uri.request_uri req.set_form_data params req end def http_obj http = Net::HTTP.new uri.host, uri.port http.use_ssl = (uri.scheme == "https") http_options.each do |opt, val| if http.respond_to? "#{opt}=" http.send "#{opt}=", val else warn "Net::HTTP doesn't respond to `#{opt}=`, ignoring that option" end end http end end end end end slack-messenger-2.3.3/lib/slack-messenger/util/link_formatter.rb0000644000175000017500000000436313637141201024563 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger module Util class LinkFormatter # http://rubular.com/r/19cNXW5qbH HTML_PATTERN = %r{ (.+?) }x VALID_URI_CHARS = '\w\-\.\~\:\/\?\#\[\]\@\!\$\&\'\*\+\,\;\=' # Attempt at only matching pairs of parens per # the markdown spec http://spec.commonmark.org/0.27/#links # # https://rubular.com/r/WfdZ1arvF6PNWO MARKDOWN_PATTERN = %r{ \[ ([^\[\]]*?) \] \( ( (?:https?:\/\/|mailto:) (?:[#{VALID_URI_CHARS}]*?|[#{VALID_URI_CHARS}]*?\([#{VALID_URI_CHARS}]*?\)[#{VALID_URI_CHARS}]*?) ) \) }x class << self def format string, opts={} LinkFormatter.new(string, opts).formatted end end attr_reader :formats def initialize string, formats: %i[html markdown] @formats = formats @orig = string.respond_to?(:scrub) ? string.scrub : string end # rubocop:disable Lint/RescueWithoutErrorClass def formatted return @orig unless @orig.respond_to?(:gsub) sub_markdown_links(sub_html_links(@orig)) rescue => e raise e unless RUBY_VERSION < "2.1" && e.message.include?("invalid byte sequence") raise e, "#{e.message}. Consider including the 'string-scrub' gem to strip invalid characters" end # rubocop:enable Lint/RescueWithoutErrorClass private def sub_html_links string return string unless formats.include?(:html) string.gsub(HTML_PATTERN) do slack_link Regexp.last_match[1], Regexp.last_match[2] end end def sub_markdown_links string return string unless formats.include?(:markdown) string.gsub(MARKDOWN_PATTERN) do slack_link Regexp.last_match[2], Regexp.last_match[1] end end def slack_link link, text=nil "<#{link}" \ "#{text && !text.empty? ? "|#{text}" : ''}" \ ">" end end end end end slack-messenger-2.3.3/lib/slack-messenger/util/escape.rb0000644000175000017500000000050713637141201022777 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger module Util module Escape HTML_REGEXP = /[&><]/ HTML_REPLACE = { "&" => "&", ">" => ">", "<" => "<" }.freeze def self.html string string.gsub(HTML_REGEXP, HTML_REPLACE) end end end end end slack-messenger-2.3.3/lib/slack-messenger/version.rb0000644000175000017500000000021513637141201022243 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger VERSION = "2.3.3".freeze # rubocop:disable Style/RedundantFreeze end end slack-messenger-2.3.3/lib/slack-messenger/payload_middleware.rb0000644000175000017500000000107513637141201024411 0ustar abhinavabhinav# frozen_string_literal: true module Slack class Messenger class PayloadMiddleware class << self def registry @registry ||= {} end def register middleware, name registry[name] = middleware end end end end end require_relative "payload_middleware/stack" require_relative "payload_middleware/base" require_relative "payload_middleware/format_message" require_relative "payload_middleware/format_attachments" require_relative "payload_middleware/at" require_relative "payload_middleware/channels" slack-messenger-2.3.3/lib/slack-messenger.rb0000644000175000017500000000257413637141201020570 0ustar abhinavabhinav# frozen_string_literal: true require "uri" require "json" require_relative "slack-messenger/util/http_client" require_relative "slack-messenger/util/link_formatter" require_relative "slack-messenger/util/escape" require_relative "slack-messenger/payload_middleware" require_relative "slack-messenger/config" module Slack class Messenger attr_reader :endpoint def initialize webhook_url, options={}, &block @endpoint = URI.parse webhook_url config.http_client(options.delete(:http_client)) if options.key?(:http_client) config.defaults options config.instance_exec(&block) if block_given? middleware.set config.middleware end def config @_config ||= Config.new end def ping message, options={} if message.is_a?(Hash) options = message else options[:text] = message end post options end def post payload={} params = {} client = payload.delete(:http_client) || config.http_client payload = config.defaults.merge(payload) params[:http_options] = payload.delete(:http_options) if payload.key?(:http_options) middleware.call(payload).map do |pld| params[:payload] = pld.to_json client.post endpoint, params end end private def middleware @middleware ||= PayloadMiddleware::Stack.new(self) end end end slack-messenger-2.3.3/spec/0000755000175000017500000000000013637141201015334 5ustar abhinavabhinavslack-messenger-2.3.3/spec/integration/0000755000175000017500000000000013637141201017657 5ustar abhinavabhinavslack-messenger-2.3.3/spec/integration/ping_integration_test.rb0000644000175000017500000000102313637141201024577 0ustar abhinavabhinav# frozen_string_literal: true # encoding: utf-8 require_relative "../../lib/slack-messenger" ruby = if defined?(JRUBY_VERSION) "jruby #{JRUBY_VERSION}" else "ruby #{RUBY_VERSION}" end puts "testing with #{ruby}" messenger = Slack::Messenger.new ENV["SLACK_WEBHOOK_URL"], username: "messenger" messenger.ping "hello", channel: ["#general", "#random"] messenger.ping "hello/こんにちは from messenger test script on #{ruby}\225" messenger.ping attachments: [{ color: "#1BF5AF", fallback: "fallback", text: "attachment" }] slack-messenger-2.3.3/spec/lib/0000755000175000017500000000000013637141201016102 5ustar abhinavabhinavslack-messenger-2.3.3/spec/lib/slack-messenger/0000755000175000017500000000000013637141201021165 5ustar abhinavabhinavslack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/0000755000175000017500000000000013637141201025013 5ustar abhinavabhinavslack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/format_message_spec.rb0000644000175000017500000000173213637141201031351 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware::FormatMessage do it "passes the text through linkformatter with options[:formats]" do subject = described_class.new(:messenger, formats: [:html]) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: [:html]) subject.call(text: "hello") subject = described_class.new(:messenger) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: %i[html markdown]) subject.call(text: "hello") subject = described_class.new(:messenger, formats: [:markdown]) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: [:markdown]) subject.call(text: "hello") end it "returns the payload unmodified if not :text key" do payload = { foo: :bar } subject = described_class.new(:messenger) expect(subject.call(payload)).to eq payload end end slack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/channels_spec.rb0000644000175000017500000000115713637141201030151 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware::Channels do it "leaves string channels alone" do subject = described_class.new(:messenger) payload = { text: "hello", channel: "hodor" } expect(subject.call(payload)).to eq text: "hello", channel: "hodor" end it "splits payload into multiple if given an array of channels" do subject = described_class.new(:messenger) payload = { text: "hello", channel: %w[foo hodor] } expect(subject.call(payload)).to eq [ { text: "hello", channel: "foo" }, { text: "hello", channel: "hodor" } ] end end slack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/at_spec.rb0000644000175000017500000000147613637141201026766 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware::At do it "can handle array at" do subject = described_class.new(:messenger) payload = { text: "hello", at: %i[john ken here] } expect(subject.call(payload)).to eq text: "<@john> <@ken> hello" end it "can handle single at option" do subject = described_class.new(:messenger) payload = { text: "hello", at: :alice } expect(subject.call(payload)).to eq text: "<@alice> hello" end it "generates :text in payload if given :at & no :text" do subject = described_class.new(:messenger) input_payload = { at: [:here], attachments: [{ text: "hello" }] } output_payload = { text: " ", attachments: [{ text: "hello" }] } expect(subject.call(input_payload)).to eq output_payload end end slack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/stack_spec.rb0000644000175000017500000000756213637141201027471 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware::Stack do let(:return_one) do double(call: 1) end let(:return_one_twice) do double(call: [1, 1]) end let(:return_two) do double(call: 2) end let(:return_three) do double(call: 3) end before(:each) do # setup our middleware in the registry @registry_backup = Slack::Messenger::PayloadMiddleware.registry.dup Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry) Slack::Messenger::PayloadMiddleware.register return_one, :return_one Slack::Messenger::PayloadMiddleware.register return_one_twice, :return_one_twice Slack::Messenger::PayloadMiddleware.register return_two, :return_two Slack::Messenger::PayloadMiddleware.register return_three, :return_three end after(:each) do # cleanup middleware registry Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry) Slack::Messenger::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup) end describe "::initialize" do it "sets messenger to given messenger" do expect(described_class.new(:messenger).messenger).to eq :messenger end it "has empty stack" do expect(described_class.new(:messenger).stack).to match_array [] end end describe "#set" do it "initializes each middleware w/ the messenger instance" do expect(return_one).to receive(:new).with(:messenger) expect(return_two).to receive(:new).with(:messenger) described_class.new(:messenger).set(:return_one, :return_two) end it "creates the stack in an array" do allow(return_one).to receive(:new).and_return(return_one) allow(return_two).to receive(:new).and_return(return_two) subject = described_class.new(:messenger) subject.set(:return_one, :return_two) expect(subject.stack).to be_a Array expect(subject.stack.first.call).to eq 1 expect(subject.stack.last.call).to eq 2 end it "creates a stack from hashes passing them as opts" do expect(return_one).to receive(:new).with(:messenger, opts: :for_one) expect(return_two).to receive(:new).with(:messenger, opts: :for_two) subject = described_class.new(:messenger) subject.set return_one: { opts: :for_one }, return_two: { opts: :for_two } end it "raises if a middleware is missing" do expect do described_class.new(:messenger).set(:missing) end.to raise_exception KeyError end end describe "#call" do it "calls the middleware in order, passing return of each to the next" do allow(return_one).to receive(:new).and_return(return_one) allow(return_two).to receive(:new).and_return(return_two) allow(return_three).to receive(:new).and_return(return_three) subject = described_class.new(:messenger) subject.set(:return_one, :return_three, :return_two) expect(return_one).to receive(:call).with(5) expect(return_three).to receive(:call).with(1) expect(return_two).to receive(:call).with(3) expect(subject.call(5)).to eq [2] end it "allows any middleware to return an array but other's don't need special behavior" do allow(return_one_twice).to receive(:new).and_return(return_one_twice) allow(return_two).to receive(:new).and_return(return_two) subject = described_class.new(:messenger) subject.set(:return_one_twice, :return_two) expect(subject.call(5)).to eq [2, 2] end it "handles multiple middleware splitting payload" do allow(return_one_twice).to receive(:new).and_return(return_one_twice) allow(return_two).to receive(:new).and_return(return_two) subject = described_class.new(:messenger) subject.set(:return_one_twice, :return_one_twice, :return_two) expect(subject.call(5)).to eq [2, 2, 2, 2] end end end slack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/format_attachments_spec.rb0000644000175000017500000000317613637141201032244 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware::FormatAttachments do it "passes the text of attachments through linkformatter with options[:formats]" do subject = described_class.new(:messenger, formats: [:html]) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: [:html]) subject.call(attachments: [{ text: "hello" }]) end it "searches through string or symbol keys" do subject = described_class.new(:messenger) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: %i[html markdown]) subject.call("attachments" => [{ "text" => "hello" }]) subject = described_class.new(:messenger) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: %i[html markdown]) subject.call(attachments: [{ text: "hello" }]) end it "can handle a single attachment" do subject = described_class.new(:messenger) expect(Slack::Messenger::Util::LinkFormatter).to receive(:format) .with("hello", formats: %i[html markdown]) subject.call(attachments: { text: "hello" }) end it "wraps attachment into array if given as a single hash" do params = { attachments: { text: "hello" } } payload = { attachments: [{ text: "hello" }] } subject = described_class.new(:messenger) expect(subject.call(params)).to eq payload end it "returns the payload unmodified if not :attachments key" do payload = { foo: :bar } subject = described_class.new(:messenger) expect(subject.call(payload)).to eq payload end end slack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware/base_spec.rb0000644000175000017500000000423313637141201027266 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware::Base do before(:each) do @registry_backup = Slack::Messenger::PayloadMiddleware.registry.dup Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry) end after(:each) do # cleanup middleware registry Slack::Messenger::PayloadMiddleware.registry Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry) # cleanup object constants Object.send(:remove_const, :Subject) if Object.constants.include?(:Subject) Slack::Messenger::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup) end describe "::middleware_name" do it "registers class w/ given name" do class Subject < Slack::Messenger::PayloadMiddleware::Base end expect(Slack::Messenger::PayloadMiddleware) .to receive(:register).with(Subject, :subject) class Subject middleware_name :subject end end it "uses symbolized name to register" do class Subject < Slack::Messenger::PayloadMiddleware::Base end expect(Slack::Messenger::PayloadMiddleware) .to receive(:register).with(Subject, :subject) class Subject middleware_name "subject" end end end describe "::options" do it "allows setting default options for a middleware" do class Subject < Slack::Messenger::PayloadMiddleware::Base options foo: :bar end subject = Subject.new(:messenger) expect(subject.options).to eq foo: :bar subject = Subject.new(:messenger, foo: :baz) expect(subject.options).to eq foo: :baz end end describe "#initialize" do it "sets given messenger as messenger" do expect(described_class.new(:messenger).messenger).to eq :messenger end it "sets given options as opts" do expect(described_class.new(:messenger, opts: :options).options).to eq opts: :options end end describe "#call" do it "raises NoMethodError (expects subclass to define)" do expect do described_class.new(:messenger).call end.to raise_exception NoMethodError end end end slack-messenger-2.3.3/spec/lib/slack-messenger/util/0000755000175000017500000000000013637141201022142 5ustar abhinavabhinavslack-messenger-2.3.3/spec/lib/slack-messenger/util/link_formatter_spec.rb0000644000175000017500000001645713637141201026536 0ustar abhinavabhinav# frozen_string_literal: true # encoding: utf-8 # rubocop:disable Metrics/LineLength RSpec.describe Slack::Messenger::Util::LinkFormatter do describe "::format" do it "formats html links" do formatted = described_class.format("Hello World, enjoy this.") expect(formatted).to include("") end it "formats markdown links" do formatted = described_class.format("Hello World, enjoy [this](http://example.com).") expect(formatted).to include("") end it "formats markdown links in brackets" do formatted = described_class.format("Hello World, enjoy [[this](http://example.com) in brackets].") expect(formatted).to eq("Hello World, enjoy [ in brackets].") end it "formats markdown links with no title" do formatted = described_class.format("Hello World, enjoy [](http://example.com).") expect(formatted).to include("") end it "handles multiple html links" do formatted = described_class.format("Hello World, enjoy thisthis2.") expect(formatted).to include("") expect(formatted).to include("") end it "handles multiple markdown links" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)[this2](http://example2.com).") expect(formatted).to include("") expect(formatted).to include("") end it "handles mixed html & markdown links" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)this2.") expect(formatted).to include("") expect(formatted).to include("") end if "".respond_to? :scrub context "when on ruby 2.1+ or have string-scrub installed" do it "handles invalid unicode sequences" do expect do described_class.format("This sequence is invalid: \255") end.not_to raise_error end it "replaces invalid unicode sequences with the unicode replacement character" do formatted = described_class.format("\255") expect(formatted).to eq "\uFFFD" end end end it "doesn't replace valid Japanese" do formatted = described_class.format("こんにちは") expect(formatted).to eq "こんにちは" end it "handles mailto links in markdown" do formatted = described_class.format("[John](mailto:john@example.com)") expect(formatted).to eq "" end it "handles mailto links in html" do formatted = described_class.format("John") expect(formatted).to eq "" end it "handles links with trailing parentheses" do formatted = described_class.format("Hello World, enjoy [foo(bar)](http://example.com/foo(bar))bar(foo)") expect(formatted).to include("http://example.com/foo(bar)|foo(bar)") expect(formatted).to include("http://example.com/bar(foo)|bar(foo)") end it "formats a number of differently formatted links" do input_output = { "Hello World, enjoy [this](http://example.com)." => "Hello World, enjoy .", "Hello World, enjoy [[this](http://example.com) in brackets]." => "Hello World, enjoy [ in brackets].", "Hello World, enjoy ([this](http://example.com) in parens)." => "Hello World, enjoy ( in parens).", "Hello World, enjoy ([this](http://example.com))." => "Hello World, enjoy ().", "Hello World, enjoy [](http://example.com)." => "Hello World, enjoy .", "Hello World, enjoy [link with query](http://example.com?foo=bar)." => "Hello World, enjoy .", "Hello World, enjoy [link with fragment](http://example.com/#foo-bar)." => "Hello World, enjoy .", "Hello World, enjoy [link with parens](http://example.com/foo(bar)/baz)." => "Hello World, enjoy .", "Hello World, enjoy [link with query](http://example.com/(parens)?foo=bar)." => "Hello World, enjoy .", "Hello World, enjoy [link with parens](http://example.com/baz?bang=foo(bar))." => "Hello World, enjoy .", "Hello World, enjoy [link with fragment](http://example.com/(parens)#foo-bar)." => "Hello World, enjoy .", "Hello World, enjoy [link with fragment](http://example.com/#foo-bar=(baz))." => "Hello World, enjoy .", "Hello World, enjoy [this](http://example.com?foo=bar)[this2](http://example2.com)." => "Hello World, enjoy .", "Hello World, enjoy [this](http://example.com?foo=bar) [this2](http://example2.com/#fragment)." => "Hello World, enjoy .", "Hello World, enjoy [this](http://example.com)this2." => "Hello World, enjoy .", "Hello world, [John](mailto:john@example.com)." => "Hello world, .", "Hello World, enjoy [foo(bar)](http://example.com/foo(bar))bar(foo)" => "Hello World, enjoy " } input_output.each do |input, output| expect(described_class.format(input)).to eq output end end context "with a configured stack" do it "only formats html if html is the only item in formats" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)this2.", formats: [:html]) expect(formatted).to eq "Hello World, enjoy [this](http://example.com)." end it "only formats markdown if markdown is the only item in formats" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)this2.", formats: [:markdown]) expect(formatted).to eq "Hello World, enjoy this2." end it "doesn't format if formats is empty" do formatted = described_class.format("Hello World, enjoy [this](http://example.com)this2.", formats: []) expect(formatted).to eq "Hello World, enjoy [this](http://example.com)this2." end end end end slack-messenger-2.3.3/spec/lib/slack-messenger/util/http_client_spec.rb0000644000175000017500000000372113637141201026021 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::Util::HTTPClient do describe "::post" do it "initializes Util::HTTPClient with the given uri and params then calls" do http_post_double = instance_double("Slack::Messenger::Util::HTTPClient") expect(described_class) .to receive(:new).with("uri", "params") .and_return(http_post_double) expect(http_post_double).to receive(:call) described_class.post "uri", "params" end # http_post is really tested in the integration spec, # where the internals are run through end describe "#initialize" do it "allows setting of options for Net::HTTP" do net_http_double = instance_double("Net::HTTP") http_client = described_class.new URI.parse("http://example.com"), http_options: { open_timeout: 5 } allow(Net::HTTP).to receive(:new).and_return(net_http_double) allow(net_http_double).to receive(:use_ssl=) allow(net_http_double).to receive(:request).with(anything) do Net::HTTPOK.new("GET", "200", "OK") end expect(net_http_double).to receive(:open_timeout=).with(5) http_client.call end end describe "#call" do it "raises an error when the response is unsuccessful" do net_http_double = instance_double("Net::HTTP") http_client = described_class.new URI.parse("http://example.com"), {} bad_request = Net::HTTPBadRequest.new("GET", "400", "Bad Request") allow(bad_request).to receive(:body).and_return("something_bad") allow(Net::HTTP).to receive(:new).and_return(net_http_double) allow(net_http_double).to receive(:use_ssl=) allow(net_http_double).to receive(:request).with(anything) do bad_request end expect { http_client.call }.to raise_error(Slack::Messenger::APIError, /something_bad \(HTTP Code 400\)/) end end end slack-messenger-2.3.3/spec/lib/slack-messenger/payload_middleware_spec.rb0000644000175000017500000000171413637141201026355 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::PayloadMiddleware do before(:each) do @registry_backup = described_class.registry.dup Slack::Messenger::PayloadMiddleware.send(:remove_instance_variable, :@registry) end after(:each) do described_class.send(:remove_instance_variable, :@registry) described_class.send(:instance_variable_set, :@registry, @registry_backup) end describe "::registry" do it "returns a hash if nothing set" do expect(described_class.registry).to eq({}) end it "returns memoized version if already set" do described_class.instance_variable_set(:@registry, "hodor") expect(described_class.registry).to eq "hodor" end end describe "::register" do it "adds given class to key in registry" do MyClass = Struct.new(:myclass) described_class.register MyClass, :my_class expect(described_class.registry[:my_class]).to eq MyClass end end end slack-messenger-2.3.3/spec/lib/slack-messenger/config_spec.rb0000644000175000017500000000407213637141201023774 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger::Config do describe "#http_client" do it "is Util::HTTPClient if not set" do subject = described_class.new expect(subject.http_client).to eq Slack::Messenger::Util::HTTPClient end it "sets a new client class if given one" do new_client = class_double("Slack::Messenger::Util::HTTPClient", post: nil) subject = described_class.new subject.http_client new_client expect(subject.http_client).to eq new_client end it "raises an ArgumentError if given class does not respond to ::post" do subject = described_class.new expect do subject.http_client :nope end.to raise_error ArgumentError end end describe "#defaults" do it "is an empty hash by default" do subject = described_class.new expect(subject.defaults).to eq({}) end it "sets a hash to default if given" do subject = described_class.new subject.defaults foo: :bar expect(subject.defaults).to eq foo: :bar end it "raises ArgumentError if not given a hash" do subject = described_class.new expect do subject.defaults :nope end.to raise_error ArgumentError end end describe "#middleware" do it "is [:format_message, :format_attachments, :at] if not set" do subject = described_class.new expect(subject.middleware).to eq %i[format_message format_attachments at channels] end it "takes an array or a splat of args" do subject = described_class.new subject.middleware :layer, :two expect(subject.middleware).to eq %i[layer two] subject.middleware %i[one layer] expect(subject.middleware).to eq %i[one layer] end it "allows passing options to middleware stack" do subject = described_class.new subject.middleware one: { opts: :for_one }, two: { opts: :for_two } expect(subject.middleware).to eq one: { opts: :for_one }, two: { opts: :for_two } end end end slack-messenger-2.3.3/spec/lib/slack-messenger_spec.rb0000644000175000017500000000560213637141201022527 0ustar abhinavabhinav# frozen_string_literal: true RSpec.describe Slack::Messenger do let(:mock_http) do class_double("Slack::Messenger::Util::HTTPClient", post: :posted) end subject { described_class.new "http://example.com", http_client: mock_http } describe "#initialize" do it "sets the given hook_url to the endpoint URI" do expect(subject.endpoint).to eq URI.parse("http://example.com") end it "sets the default_payload options" do subject = described_class.new "http://example.com", channel: "foo" expect(subject.config.defaults[:channel]).to eq "foo" end it "sets a custom http client" do subject = described_class.new "http://example.com", http_client: mock_http expect(subject.config.http_client).to eq mock_http end describe "when given a block" do it "yields the config object" do test_double = double("Slack::Messenger::Config", defaults: {}, middleware: []) allow_any_instance_of(Slack::Messenger).to receive(:config).and_return(test_double) expect(test_double).to receive(:test_init_method).with("foo") described_class.new "http://example.com" do test_init_method "foo" end end end end describe "#ping" do it "calls #post with the message as the text key in #post" do subject = described_class.new "http://example.com" expect(subject).to receive(:post).with text: "message" subject.ping "message" end end describe "#post" do def messenger_with_defaults mock_client = mock_http described_class.new "http://example.com" do defaults channel: "default", user: "rocket" http_client mock_client end end it "uses the defaults set on initialization" do subject = messenger_with_defaults expect(mock_http).to receive(:post).with( URI.parse("http://example.com"), payload: '{"channel":"default","user":"rocket","text":"hello"}' ) subject.post text: "hello" end it "allows overriding the set defaults" do subject = messenger_with_defaults expect(mock_http).to receive(:post).with( URI.parse("http://example.com"), payload: '{"channel":"new","user":"ship","text":"hello"}' ) subject.post text: "hello", channel: "new", user: "ship" end it "calls the middleware stack with the payload" do subject = messenger_with_defaults stack = instance_double("Slack::Messenger::PayloadMiddleware::Stack") subject.instance_variable_set(:@middleware, stack) expect(stack).to receive(:call) .with(channel: "default", user: "rocket") .and_return([test: "stack"]) expect(mock_http).to receive(:post).with( URI.parse("http://example.com"), payload: '{"test":"stack"}' ) responses = subject.post expect(responses).to eq([:posted]) end end end slack-messenger-2.3.3/spec/end_to_end_spec.rb0000644000175000017500000000753113637141201020777 0ustar abhinavabhinav# frozen_string_literal: true # encoding: utf-8 require "spec_helper" RSpec.describe Slack::Messenger do { { text: "hello" } => { payload: { text: "hello" } }, { text: "[hello](http://example.com/world)" } => { payload: { text: "" } }, { text: 'example' } => { payload: { text: "" } }, { text: "hello/こんにちは from messenger test" } => { payload: { text: "hello/こんにちは from messenger test" } }, { text: "Hello World, enjoy [](http://example.com)." } => { payload: { text: "Hello World, enjoy ." } }, { text: "Hello World, enjoy [this](http://example.com)[this2](http://example2.com)" } => { payload: { text: "Hello World, enjoy " } }, { text: "[John](mailto:john@example.com)" } => { payload: { text: "" } }, { text: 'John' } => { payload: { text: "" } }, { text: "hello", channel: "hodor" } => { payload: { text: "hello", channel: "hodor" } }, { text: nil, attachments: [{ text: "attachment message" }] } => { payload: { text: nil, attachments: [{ text: "attachment message" }] } }, { text: "the message", channel: "foo", attachments: [{ color: "#000", text: "attachment message", fallback: "fallback message" }] } => { payload: { text: "the message", channel: "foo", attachments: [{ color: "#000", text: "attachment message", fallback: "fallback message" }] } }, { attachments: [{ color: "#000", text: "attachment message", fallback: "fallback message" }] } => { payload: { attachments: [{ color: "#000", text: "attachment message", fallback: "fallback message" }] } }, { attachments: { color: "#000", text: "attachment message [hodor](http://winterfell.com)", fallback: "fallback message" } } => { payload: { attachments: [{ color: "#000", text: "attachment message ", fallback: "fallback message" }] } }, { attachments: { color: "#000", text: nil, fallback: "fallback message" } } => { payload: { attachments: [{ color: "#000", text: nil, fallback: "fallback message" }] } }, { text: "hello", http_options: { timeout: 5 } } => { http_options: { timeout: 5 }, payload: { text: "hello" } } }.each do |args, payload| it "sends correct payload for #post(#{args})" do http_client = class_double("Slack::Messenger::Util::HTTPClient", post: nil) messenger = Slack::Messenger.new "http://example.com", http_client: http_client payload[:payload] = payload[:payload].to_json expect(http_client).to receive(:post) .with(URI.parse("http://example.com"), payload) messenger.post(args) end end it "applies options given to middleware" do client = class_double("Slack::Messenger::Util::HTTPClient", post: nil) messenger = Slack::Messenger.new "http://example.com" do http_client client middleware format_message: { formats: [] } end expect(client).to receive(:post) .with(URI.parse("http://example.com"), payload: { text: "Hello [world](http://example.com)!" }.to_json) messenger.post text: "Hello [world](http://example.com)!" end end slack-messenger-2.3.3/spec/spec_helper.rb0000644000175000017500000000135413637141201020155 0ustar abhinavabhinav# frozen_string_literal: true require "rspec" require "slack-messenger" require "pry" if ENV["DEBUG"] RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_doubled_constant_names = true mocks.verify_partial_doubles = true end config.filter_run :focus config.run_all_when_everything_filtered = true config.disable_monkey_patching! config.example_status_persistence_file_path = "spec/examples.txt" config.warnings = ENV["DEBUG"] ? false : true config.default_formatter = "doc" if config.files_to_run.one? config.order = :random Kernel.srand config.seed end