slack-ruby-bot-bhe 0.5.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +17 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +6 -0
  5. data/.rubocop_todo.yml +58 -0
  6. data/.travis.yml +3 -0
  7. data/CHANGELOG.md +81 -0
  8. data/CONTRIBUTING.md +139 -0
  9. data/DEPLOYMENT.md +33 -0
  10. data/Gemfile +3 -0
  11. data/LICENSE.md +22 -0
  12. data/README.md +263 -0
  13. data/RELEASING.md +67 -0
  14. data/Rakefile +19 -0
  15. data/TUTORIAL.md +205 -0
  16. data/UPGRADING.md +64 -0
  17. data/examples/minimal/Gemfile +3 -0
  18. data/examples/minimal/Procfile +1 -0
  19. data/examples/minimal/pongbot.rb +9 -0
  20. data/examples/weather/Gemfile +3 -0
  21. data/examples/weather/Procfile +1 -0
  22. data/examples/weather/weatherbot.rb +9 -0
  23. data/lib/config/application.rb +14 -0
  24. data/lib/config/boot.rb +8 -0
  25. data/lib/config/environment.rb +3 -0
  26. data/lib/initializers/giphy.rb +5 -0
  27. data/lib/slack-ruby-bot.rb +25 -0
  28. data/lib/slack-ruby-bot/about.rb +7 -0
  29. data/lib/slack-ruby-bot/app.rb +46 -0
  30. data/lib/slack-ruby-bot/bot.rb +7 -0
  31. data/lib/slack-ruby-bot/client.rb +44 -0
  32. data/lib/slack-ruby-bot/commands.rb +5 -0
  33. data/lib/slack-ruby-bot/commands/about.rb +12 -0
  34. data/lib/slack-ruby-bot/commands/base.rb +121 -0
  35. data/lib/slack-ruby-bot/commands/help.rb +9 -0
  36. data/lib/slack-ruby-bot/commands/hi.rb +9 -0
  37. data/lib/slack-ruby-bot/commands/unknown.rb +11 -0
  38. data/lib/slack-ruby-bot/config.rb +40 -0
  39. data/lib/slack-ruby-bot/hooks.rb +3 -0
  40. data/lib/slack-ruby-bot/hooks/base.rb +10 -0
  41. data/lib/slack-ruby-bot/hooks/hello.rb +11 -0
  42. data/lib/slack-ruby-bot/hooks/message.rb +50 -0
  43. data/lib/slack-ruby-bot/rspec.rb +12 -0
  44. data/lib/slack-ruby-bot/rspec/support/fixtures/slack/auth_test.yml +16 -0
  45. data/lib/slack-ruby-bot/rspec/support/fixtures/slack/migration_in_progress.yml +30 -0
  46. data/lib/slack-ruby-bot/rspec/support/slack-ruby-bot/it_behaves_like_a_slack_bot.rb +27 -0
  47. data/lib/slack-ruby-bot/rspec/support/slack-ruby-bot/respond_with_error.rb +30 -0
  48. data/lib/slack-ruby-bot/rspec/support/slack-ruby-bot/respond_with_slack_message.rb +19 -0
  49. data/lib/slack-ruby-bot/rspec/support/slack_api_key.rb +5 -0
  50. data/lib/slack-ruby-bot/rspec/support/slack_ruby_bot_configure.rb +9 -0
  51. data/lib/slack-ruby-bot/rspec/support/vcr.rb +8 -0
  52. data/lib/slack-ruby-bot/server.rb +111 -0
  53. data/lib/slack-ruby-bot/version.rb +3 -0
  54. data/lib/slack_ruby_bot.rb +1 -0
  55. data/screenshots/aliases.gif +0 -0
  56. data/screenshots/demo.gif +0 -0
  57. data/screenshots/dms.gif +0 -0
  58. data/screenshots/register-bot.png +0 -0
  59. data/screenshots/weather.gif +0 -0
  60. data/slack-ruby-bot.gemspec +28 -0
  61. data/slack.png +0 -0
  62. data/spec/slack-ruby-bot/app_spec.rb +15 -0
  63. data/spec/slack-ruby-bot/commands/about_spec.rb +19 -0
  64. data/spec/slack-ruby-bot/commands/aliases_spec.rb +22 -0
  65. data/spec/slack-ruby-bot/commands/bot_spec.rb +19 -0
  66. data/spec/slack-ruby-bot/commands/commands_precedence_spec.rb +22 -0
  67. data/spec/slack-ruby-bot/commands/commands_regexp_escape_spec.rb +17 -0
  68. data/spec/slack-ruby-bot/commands/commands_spaces_spec.rb +20 -0
  69. data/spec/slack-ruby-bot/commands/commands_spec.rb +21 -0
  70. data/spec/slack-ruby-bot/commands/commands_with_block_spec.rb +23 -0
  71. data/spec/slack-ruby-bot/commands/direct_messages_spec.rb +38 -0
  72. data/spec/slack-ruby-bot/commands/empty_text_spec.rb +22 -0
  73. data/spec/slack-ruby-bot/commands/help_spec.rb +10 -0
  74. data/spec/slack-ruby-bot/commands/hi_spec.rb +19 -0
  75. data/spec/slack-ruby-bot/commands/match_spec.rb +17 -0
  76. data/spec/slack-ruby-bot/commands/message_loop_spec.rb +34 -0
  77. data/spec/slack-ruby-bot/commands/nil_message_spec.rb +22 -0
  78. data/spec/slack-ruby-bot/commands/not_implemented_spec.rb +15 -0
  79. data/spec/slack-ruby-bot/commands/operators_spec.rb +20 -0
  80. data/spec/slack-ruby-bot/commands/operators_with_block_spec.rb +23 -0
  81. data/spec/slack-ruby-bot/commands/send_gif_spec.rb +32 -0
  82. data/spec/slack-ruby-bot/commands/send_message_spec.rb +19 -0
  83. data/spec/slack-ruby-bot/commands/send_message_with_gif_spec.rb +73 -0
  84. data/spec/slack-ruby-bot/commands/unknown_spec.rb +18 -0
  85. data/spec/slack-ruby-bot/config_spec.rb +55 -0
  86. data/spec/slack-ruby-bot/rspec/respond_with_error_spec.rb +19 -0
  87. data/spec/slack-ruby-bot/server_spec.rb +73 -0
  88. data/spec/slack-ruby-bot/version_spec.rb +7 -0
  89. data/spec/spec_helper.rb +1 -0
  90. metadata +313 -0
@@ -0,0 +1,27 @@
1
+ shared_examples 'a slack ruby bot' do
2
+ context 'not configured' do
3
+ before do
4
+ @slack_api_token = ENV.delete('SLACK_API_TOKEN')
5
+ end
6
+ after do
7
+ ENV['SLACK_API_TOKEN'] = @slack_api_token
8
+ end
9
+ it 'requires SLACK_API_TOKEN' do
10
+ expect { subject }.to raise_error RuntimeError, "Missing ENV['SLACK_API_TOKEN']."
11
+ end
12
+ end
13
+ context 'configured', vcr: { cassette_name: 'auth_test' } do
14
+ context 'run' do
15
+ before do
16
+ subject.send(:auth!)
17
+ end
18
+ it 'succeeds auth' do
19
+ expect(subject.config.url).to eq 'https://rubybot.slack.com/'
20
+ expect(subject.config.team).to eq 'team_name'
21
+ expect(subject.config.user).to eq 'user_name'
22
+ expect(subject.config.team_id).to eq 'TDEADBEEF'
23
+ expect(subject.config.user_id).to eq 'UBAADFOOD'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :respond_with_error do |error, error_message|
4
+ match do |actual|
5
+ channel, user, message = parse(actual)
6
+ allow(Giphy).to receive(:random)
7
+ begin
8
+ expect do
9
+ client = app.send(:client)
10
+ app.send(:message, client, text: message, channel: channel, user: user)
11
+ end.to raise_error error, error_message
12
+ rescue RSpec::Expectations::ExpectationNotMetError => e
13
+ @error_message = e.message
14
+ raise e
15
+ end
16
+ true
17
+ end
18
+
19
+ failure_message do |actual|
20
+ _, _, message = parse(actual)
21
+ @error_message || "expected for '#{message}' to fail with '#{expected}'"
22
+ end
23
+
24
+ private
25
+
26
+ def parse(actual)
27
+ actual = { message: actual } unless actual.is_a?(Hash)
28
+ [actual[:channel] || 'channel', actual[:user] || 'user', actual[:message]]
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :respond_with_slack_message do |expected|
4
+ match do |actual|
5
+ channel, user, message = parse(actual)
6
+ allow(Giphy).to receive(:random)
7
+ client = app.send(:client)
8
+ expect(SlackRubyBot::Commands::Base).to receive(:send_client_message).with(client, channel: channel, text: expected)
9
+ app.send(:message, client, text: message, channel: channel, user: user)
10
+ true
11
+ end
12
+
13
+ private
14
+
15
+ def parse(actual)
16
+ actual = { message: actual } unless actual.is_a?(Hash)
17
+ [actual[:channel] || 'channel', actual[:user] || 'user', actual[:message]]
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.configure do |config|
2
+ config.before :all do
3
+ ENV['SLACK_API_TOKEN'] ||= 'test'
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.configure do |config|
2
+ config.before :each do
3
+ SlackRubyBot.configure do |c|
4
+ c.token = 'testtoken'
5
+ c.user = 'rubybot'
6
+ c.user_id = 'DEADBEEF'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ require 'vcr'
2
+
3
+ VCR.configure do |config|
4
+ config.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures/slack')
5
+ config.hook_into :webmock
6
+ # config.default_cassette_options = { record: :new_episodes }
7
+ config.configure_rspec_metadata!
8
+ end
@@ -0,0 +1,111 @@
1
+ module SlackRubyBot
2
+ class Server
3
+ cattr_accessor :hooks
4
+ attr_accessor :token
5
+ attr_accessor :aliases
6
+ attr_accessor :send_gifs
7
+
8
+ include SlackRubyBot::Hooks::Hello
9
+ include SlackRubyBot::Hooks::Message
10
+
11
+ def initialize(options = {})
12
+ @token = options[:token]
13
+ @aliases = options[:aliases]
14
+ @send_gifs = options.key?(:send_gifs) ? !!options[:send_gifs] : true
15
+ end
16
+
17
+ def run
18
+ auth!
19
+ loop do
20
+ begin
21
+ start!
22
+ rescue Slack::Web::Api::Error => e
23
+ logger.error e
24
+ case e.message
25
+ when 'migration_in_progress'
26
+ sleep 1 # ignore, try again
27
+ else
28
+ raise e
29
+ end
30
+ rescue Faraday::Error::TimeoutError, Faraday::Error::ConnectionFailed, Faraday::Error::SSLError => e
31
+ logger.error e
32
+ sleep 1 # ignore, try again
33
+ rescue StandardError => e
34
+ logger.error e
35
+ raise e
36
+ ensure
37
+ @client = nil
38
+ end
39
+ end
40
+ end
41
+
42
+ def auth!
43
+ client.auth = client.web_client.auth_test
44
+ logger.info "Welcome '#{client.auth['user']}' to the '#{client.auth['team']}' team at #{client.auth['url']}."
45
+ end
46
+
47
+ def start!
48
+ @stopping = false
49
+ @async = false
50
+ client.start!
51
+ end
52
+
53
+ def start_async
54
+ @stopping = false
55
+ @async = true
56
+ client.start_async
57
+ end
58
+
59
+ def stop!
60
+ @stopping = true
61
+ client.stop! if @client
62
+ end
63
+
64
+ def restart!(wait = 1)
65
+ if @async
66
+ start_async
67
+ else
68
+ start!
69
+ end
70
+ rescue StandardError => e
71
+ sleep wait
72
+ logger.error "#{e.message}, reconnecting in #{wait} second(s)."
73
+ logger.debug e
74
+ restart! [wait * 2, 60].min
75
+ end
76
+
77
+ private
78
+
79
+ def logger
80
+ @logger ||= begin
81
+ $stdout.sync = true
82
+ Logger.new(STDOUT)
83
+ end
84
+ end
85
+
86
+ def client
87
+ @client ||= begin
88
+ client = SlackRubyBot::Client.new(aliases: aliases, send_gifs: send_gifs, token: token)
89
+ client.on :close do |_data|
90
+ @client = nil
91
+ restart! unless @stopping
92
+ end
93
+ hooks.each do |hook|
94
+ client.on hook do |data|
95
+ begin
96
+ send hook, client, data
97
+ rescue StandardError => e
98
+ logger.error e
99
+ begin
100
+ client.message(channel: data['channel'], text: e.message) if data.key?('channel')
101
+ rescue
102
+ # ignore
103
+ end
104
+ end
105
+ end
106
+ end
107
+ client
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ module SlackRubyBot
2
+ VERSION = '0.5.5.3'
3
+ end
@@ -0,0 +1 @@
1
+ require 'slack-ruby-bot'
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
+ require 'slack-ruby-bot/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'slack-ruby-bot-bhe'
6
+ s.version = SlackRubyBot::VERSION
7
+ s.authors = ['Matthew Brown']
8
+ s.email = 'mbrown@bhei.com'
9
+ s.platform = Gem::Platform::RUBY
10
+ s.required_rubygems_version = '>= 1.3.6'
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- spec/*`.split("\n")
13
+ s.require_paths = ['lib']
14
+ s.homepage = 'http://github.com/mbrown-bhe/slack-ruby-bot'
15
+ s.licenses = ['MIT']
16
+ s.summary = 'The easiest way to write a Slack bot in Ruby.'
17
+ s.add_dependency 'hashie'
18
+ s.add_dependency 'slack-ruby-client-bhe', '>= 0.5.0'
19
+ s.add_dependency 'faye-websocket'
20
+ s.add_dependency 'activesupport'
21
+ s.add_dependency 'giphy', '~> 2.0.2'
22
+ s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'rspec'
24
+ s.add_development_dependency 'rack-test'
25
+ s.add_development_dependency 'vcr'
26
+ s.add_development_dependency 'webmock'
27
+ s.add_development_dependency 'rubocop', '0.32.1'
28
+ end
Binary file
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::App do
4
+ def app
5
+ SlackRubyBot::App.new
6
+ end
7
+ it_behaves_like 'a slack ruby bot'
8
+
9
+ describe '.instance' do
10
+ it 'creates an instance of the App subclass' do
11
+ klass = Class.new(SlackRubyBot::App)
12
+ expect(klass.instance.class).to be klass
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands::Default do
4
+ def app
5
+ SlackRubyBot::App.new
6
+ end
7
+ it 'lowercase' do
8
+ expect(message: SlackRubyBot.config.user).to respond_with_slack_message(SlackRubyBot::ABOUT)
9
+ end
10
+ it 'upcase' do
11
+ expect(message: SlackRubyBot.config.user.upcase).to respond_with_slack_message(SlackRubyBot::ABOUT)
12
+ end
13
+ it 'name:' do
14
+ expect(message: "#{SlackRubyBot.config.user}:").to respond_with_slack_message(SlackRubyBot::ABOUT)
15
+ end
16
+ it 'id' do
17
+ expect(message: "<@#{SlackRubyBot.config.user_id}>").to respond_with_slack_message(SlackRubyBot::ABOUT)
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot do
4
+ def app
5
+ SlackRubyBot::App.new
6
+ end
7
+ before do
8
+ ENV['SLACK_RUBY_BOT_ALIASES'] = ':emoji: alias каспаров'
9
+ end
10
+ after do
11
+ ENV.delete('SLACK_RUBY_BOT_ALIASES')
12
+ end
13
+ it 'responds to emoji' do
14
+ expect(message: ':emoji: hi').to respond_with_slack_message('Hi <@user>!')
15
+ end
16
+ it 'responds to an alias' do
17
+ expect(message: 'alias hi').to respond_with_slack_message('Hi <@user>!')
18
+ end
19
+ it 'responds to a non-English alias' do
20
+ expect(message: 'каспаров hi').to respond_with_slack_message('Hi <@user>!')
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Bot do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Bot) do
6
+ command 'bot_spec' do |client, data, match|
7
+ send_message client, data.channel, match['expression']
8
+ end
9
+ end
10
+ end
11
+ def app
12
+ SlackRubyBot::App.new
13
+ end
14
+ let(:client) { app.send(:client) }
15
+ it 'sends a message' do
16
+ expect(SlackRubyBot::Commands::Base).to receive(:send_client_message).with(client, channel: 'channel', text: 'message')
17
+ app.send(:message, client, text: "#{SlackRubyBot.config.user} bot_spec message", channel: 'channel', user: 'user')
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ command 'tomato' do |client, data, match|
7
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
8
+ end
9
+
10
+ command 'tomatoes' do |client, data, match|
11
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
12
+ end
13
+ end
14
+ end
15
+ def app
16
+ SlackRubyBot::App.new
17
+ end
18
+ it 'matches commands' do
19
+ expect(message: "#{SlackRubyBot.config.user} tomato red").to respond_with_slack_message('tomato: red')
20
+ expect(message: "#{SlackRubyBot.config.user} tomatoes green").to respond_with_slack_message('tomatoes: green')
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ command '(' do |client, data, match|
7
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
8
+ end
9
+ end
10
+ end
11
+ def app
12
+ SlackRubyBot::App.new
13
+ end
14
+ it 'does not return error' do
15
+ expect(message: "#{SlackRubyBot.config.user} ( /").to respond_with_slack_message('(: /')
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ command 'space' do |client, data, match|
7
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
8
+ end
9
+ end
10
+ end
11
+ def app
12
+ SlackRubyBot::App.new
13
+ end
14
+ it 'matches leading spaces' do
15
+ expect(message: " #{SlackRubyBot.config.user} space red").to respond_with_slack_message('space: red')
16
+ end
17
+ it 'matches trailing spaces' do
18
+ expect(message: "#{SlackRubyBot.config.user} space red ").to respond_with_slack_message('space: red')
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ command 'sayhi'
7
+ command 'saybye'
8
+
9
+ def self.call(client, data, match)
10
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
11
+ end
12
+ end
13
+ end
14
+ def app
15
+ SlackRubyBot::App.new
16
+ end
17
+ it 'supports multiple commands' do
18
+ expect(message: "#{SlackRubyBot.config.user} sayhi arg1 arg2").to respond_with_slack_message('sayhi: arg1 arg2')
19
+ expect(message: "#{SlackRubyBot.config.user} saybye arg1 arg2").to respond_with_slack_message('saybye: arg1 arg2')
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe SlackRubyBot::Commands do
4
+ let! :command do
5
+ Class.new(SlackRubyBot::Commands::Base) do
6
+ command 'sayhi' do |client, data, match|
7
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
8
+ end
9
+
10
+ command 'one', 'two' do |client, data, match|
11
+ send_message client, data.channel, "#{match[:command]}: #{match[:expression]}"
12
+ end
13
+ end
14
+ end
15
+ def app
16
+ SlackRubyBot::App.new
17
+ end
18
+ it 'supports multiple commands' do
19
+ expect(message: "#{SlackRubyBot.config.user} sayhi arg1 arg2").to respond_with_slack_message('sayhi: arg1 arg2')
20
+ expect(message: "#{SlackRubyBot.config.user} one arg1 arg2").to respond_with_slack_message('one: arg1 arg2')
21
+ expect(message: "#{SlackRubyBot.config.user} two arg1 arg2").to respond_with_slack_message('two: arg1 arg2')
22
+ end
23
+ end