Browse Source

Initial implementing, using Dentaku.

master
dblock 9 years ago
commit
7b3ec6ae1e
55 changed files with 1070 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +2
    -0
      .rspec
  3. +6
    -0
      .rubocop.yml
  4. +45
    -0
      .rubocop_todo.yml
  5. +3
    -0
      .travis.yml
  6. +3
    -0
      CHANGELOG.md
  7. +125
    -0
      CONTRIBUTING.md
  8. +25
    -0
      DEPLOYMENT.md
  9. +23
    -0
      Gemfile
  10. +105
    -0
      Gemfile.lock
  11. +22
    -0
      LICENSE.md
  12. +1
    -0
      Procfile
  13. +52
    -0
      README.md
  14. +18
    -0
      Rakefile
  15. +6
    -0
      app.json
  16. +11
    -0
      app.rb
  17. +18
    -0
      app/slack-mathbot.rb
  18. +7
    -0
      app/slack-mathbot/about.rb
  19. +83
    -0
      app/slack-mathbot/app.rb
  20. +6
    -0
      app/slack-mathbot/commands.rb
  21. +9
    -0
      app/slack-mathbot/commands/about.rb
  22. +16
    -0
      app/slack-mathbot/commands/base.rb
  23. +10
    -0
      app/slack-mathbot/commands/calculate.rb
  24. +9
    -0
      app/slack-mathbot/commands/help.rb
  25. +9
    -0
      app/slack-mathbot/commands/hi.rb
  26. +9
    -0
      app/slack-mathbot/commands/unknown.rb
  27. +13
    -0
      app/slack-mathbot/config.rb
  28. +3
    -0
      app/slack-mathbot/hooks.rb
  29. +10
    -0
      app/slack-mathbot/hooks/base.rb
  30. +11
    -0
      app/slack-mathbot/hooks/hello.rb
  31. +33
    -0
      app/slack-mathbot/hooks/message.rb
  32. +3
    -0
      app/slack-mathbot/version.rb
  33. +1
    -0
      app/slack_mathbot.rb
  34. +7
    -0
      config.ru
  35. +14
    -0
      config/application.rb
  36. +5
    -0
      config/boot.rb
  37. +3
    -0
      config/environment.rb
  38. +13
    -0
      config/initializers/slack/request.rb
  39. BIN
      screenshots/register-bot.png
  40. BIN
      screenshots/two-plus-two.gif
  41. +103
    -0
      spec/fixtures/slack/auth_test.yml
  42. +59
    -0
      spec/fixtures/slack/user_info.yml
  43. +32
    -0
      spec/slack-mathbot/app_spec.rb
  44. +10
    -0
      spec/slack-mathbot/commands/about_spec.rb
  45. +16
    -0
      spec/slack-mathbot/commands/calculate_spec.rb
  46. +7
    -0
      spec/slack-mathbot/commands/help_spec.rb
  47. +7
    -0
      spec/slack-mathbot/commands/hi_spec.rb
  48. +11
    -0
      spec/slack-mathbot/commands/unknown_spec.rb
  49. +7
    -0
      spec/slack-mathbot/version_spec.rb
  50. +12
    -0
      spec/spec_helper.rb
  51. +30
    -0
      spec/support/slack-mathbot/respond_with_error.rb
  52. +19
    -0
      spec/support/slack-mathbot/respond_with_slack_message.rb
  53. +5
    -0
      spec/support/slack_api_key.rb
  54. +4
    -0
      spec/support/slack_calculator.rb
  55. +8
    -0
      spec/support/vcr.rb

+ 1
- 0
.gitignore View File

@ -0,0 +1 @@
.env

+ 2
- 0
.rspec View File

@ -0,0 +1,2 @@
--format documentation
--color

+ 6
- 0
.rubocop.yml View File

@ -0,0 +1,6 @@
AllCops:
Exclude:
- vendor/**/*
- bin/**/*
inherit_from: .rubocop_todo.yml

+ 45
- 0
.rubocop_todo.yml View File

@ -0,0 +1,45 @@
# This configuration was generated by `rubocop --auto-gen-config`
# on 2015-06-19 13:09:29 -0400 using RuboCop version 0.31.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 1
Lint/HandleExceptions:
Enabled: false
# Offense count: 2
Metrics/AbcSize:
Max: 21
# Offense count: 1
Metrics/CyclomaticComplexity:
Max: 7
# Offense count: 19
# Configuration parameters: AllowURI, URISchemes.
Metrics/LineLength:
Max: 130
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 17
# Offense count: 16
Style/Documentation:
Enabled: false
# Offense count: 1
# Configuration parameters: Exclude.
Style/FileName:
Enabled: false
# Offense count: 1
Style/ModuleFunction:
Enabled: false
# Offense count: 1
Style/RescueModifier:
Enabled: false

+ 3
- 0
.travis.yml View File

@ -0,0 +1,3 @@
rvm:
- 2.1.6

+ 3
- 0
CHANGELOG.md View File

@ -0,0 +1,3 @@
### 0.1.0 (Next)
* Initial public release - [@dblock](https://github.com/dblock).

+ 125
- 0
CONTRIBUTING.md View File

@ -0,0 +1,125 @@
# Contributing to SlackMathbot
This project is work of [many contributors](https://github.com/dblock/slack-mathbot/graphs/contributors).
You're encouraged to submit [pull requests](https://github.com/dblock/slack-mathbot/pulls), [propose features and discuss issues](https://github.com/dblock/slack-mathbot/issues).
In the examples below, substitute your Github username for `contributor` in URLs.
## Fork the Project
Fork the [project on Github](https://github.com/dblock/slack-mathbot) and check out your copy.
```
git clone https://github.com/contributor/slack-mathbot.git
cd slack-mathbot
git remote add upstream https://github.com/dblock/slack-mathbot.git
```
## Create a Topic Branch
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
```
git checkout master
git pull upstream master
git checkout -b my-feature-branch
```
## Bundle Install and Test
Ensure that you can build the project and run tests.
```
bundle install
bundle exec rake
```
## Write Tests
Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build.
Add to [spec](spec).
We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
## Write Code
Implement your feature or bug fix.
Ruby style is enforced with [Rubocop](https://github.com/bbatsov/rubocop).
Run `bundle exec rubocop` and fix any style issues highlighted.
Make sure that `bundle exec rake` completes without errors.
## Write Documentation
Document any external behavior in the [README](README.md).
## Update Changelog
Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*.
Make it look like every other line, including your name and link to your Github account.
## Commit Changes
Make sure git knows your name and email address:
```
git config --global user.name "Your Name"
git config --global user.email "contributor@example.com"
```
Writing good commit logs is important. A commit log should describe what changed and why.
```
git add ...
git commit
```
## Push
```
git push origin my-feature-branch
```
## Make a Pull Request
Go to https://github.com/contributor/slack-mathbot and select your feature branch.
Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
## Rebase
If you've been working on a change for a while, rebase with upstream/master.
```
git fetch upstream
git rebase upstream/master
git push origin my-feature-branch -f
```
## Update CHANGELOG Again
Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows.
```
* [#123](https://github.com/dblock/slack-mathbot/pull/123): Reticulated splines - [@contributor](https://github.com/contributor).
```
Amend your previous commit and force push the changes.
```
git commit --amend
git push origin my-feature-branch -f
```
## Check on Your Pull Request
Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
## Be Patient
It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there!
## Thank You
Please do know that we really appreciate and value your time and work. We love you, really.

+ 25
- 0
DEPLOYMENT.md View File

@ -0,0 +1,25 @@
## Installation
Create a new Bot Integration under [services/new/bot](http://slack.com/services/new/bot).
![](screenshots/register-bot.png)
On the next screen, note the API token.
## Deploy Slack-Gamebot
[![Deploy to Heroku](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy)
### Environment
#### SLACK_API_TOKEN
Set SLACK_API_TOKEN from the Bot integration settings on Slack.
```
heroku config:add SLACK_API_TOKEN=...
```
### Heroku Idling
Heroku free tier applications will idle. Use [UptimeRobot](http://uptimerobot.com) or similar to prevent your instance from sleeping or pay for a production dyno.

+ 23
- 0
Gemfile View File

@ -0,0 +1,23 @@
source 'http://rubygems.org'
ruby '2.1.6'
gem 'hashie'
gem 'slack-api', '~> 1.1.6', require: 'slack'
gem 'puma'
gem 'sinatra'
gem 'activesupport'
gem 'dentaku'
group :development, :test do
gem 'rake', '~> 10.4'
gem 'rubocop', '0.31.0'
gem 'foreman'
end
group :test do
gem 'rspec', '~> 3.2'
gem 'rack-test', '~> 0.6.2'
gem 'vcr'
gem 'webmock'
end

+ 105
- 0
Gemfile.lock View File

@ -0,0 +1,105 @@
GEM
remote: http://rubygems.org/
specs:
activesupport (4.2.1)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.3.8)
ast (2.0.0)
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
crack (0.4.2)
safe_yaml (~> 1.0.0)
dentaku (1.2.6)
diff-lcs (1.2.5)
eventmachine (1.0.7)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.9.1)
faraday (>= 0.7.4, < 0.10)
faye-websocket (0.9.2)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
foreman (0.78.0)
thor (~> 0.19.1)
hashie (3.4.1)
i18n (0.7.0)
json (1.8.2)
minitest (5.6.1)
multi_json (1.11.0)
multipart-post (2.0.0)
parser (2.3.0.pre.2)
ast (>= 1.1, < 3.0)
powerpack (0.1.1)
puma (2.11.0)
rack (>= 1.1, < 2.0)
rack (1.6.0)
rack-protection (1.5.3)
rack
rack-test (0.6.3)
rack (>= 1.0)
rainbow (2.0.0)
rake (10.4.2)
rspec (3.2.0)
rspec-core (~> 3.2.0)
rspec-expectations (~> 3.2.0)
rspec-mocks (~> 3.2.0)
rspec-core (3.2.3)
rspec-support (~> 3.2.0)
rspec-expectations (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-mocks (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-support (3.2.2)
rubocop (0.31.0)
astrolabe (~> 1.3)
parser (>= 2.2.2.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
ruby-progressbar (1.7.5)
safe_yaml (1.0.4)
sinatra (1.4.5)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4)
slack-api (1.1.6)
faraday (>= 0.7, < 0.10)
faraday_middleware (~> 0.8)
faye-websocket (~> 0.9.2)
multi_json (~> 1.0, >= 1.0.3)
thor (0.19.1)
thread_safe (0.3.5)
tilt (1.4.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
vcr (2.9.3)
webmock (1.21.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
websocket-driver (0.5.4)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
PLATFORMS
ruby
DEPENDENCIES
activesupport
dentaku
foreman
hashie
puma
rack-test (~> 0.6.2)
rake (~> 10.4)
rspec (~> 3.2)
rubocop (= 0.31.0)
sinatra
slack-api (~> 1.1.6)
vcr
webmock

+ 22
- 0
LICENSE.md View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2015 Daniel Doubrovkine, Artsy and Contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 1
- 0
Procfile View File

@ -0,0 +1 @@
web: bundle exec puma -p $PORT

+ 52
- 0
README.md View File

@ -0,0 +1,52 @@
Slack-Gamebot
=============
[![Build Status](https://travis-ci.org/dblock/slack-mathbot.png)](https://travis-ci.org/dblock/slack-mathbot)
A math bot for Slack.
![](screenshots/two-plus-two.gif)
## Installation
Create a new Bot Integration under [services/new/bot](http://slack.com/services/new/bot).
![](screenshots/register-bot.png)
On the next screen, note the API token.
Run `SLACK_API_TOKEN=<your API token> foreman start`
## Production Deployment
See [DEPLOYMENT](DEPLOYMENT.md).
## Usage
### Commands
#### mathbot calculate [expression]
Calculates an expression, currently just basic math. See [Dentaku](https://github.com/rubysolo/dentaku) for what's supported.
#### mathbot
Shows MathBot version and links.
#### mathbot hi
Politely says 'hi' back.
#### mathbot help
Get help.
## Contributing
See [CONTRIBUTING](CONTRIBUTING.md).
## Copyright and License
Copyright (c) 2015, Daniel Doubrovkine, Artsy and [Contributors](CHANGELOG.md).
This project is licensed under the [MIT License](LICENSE.md).

+ 18
- 0
Rakefile View File

@ -0,0 +1,18 @@
require 'rubygems'
require 'bundler'
Bundler.setup :default, :development
unless ENV['RACK_ENV'] == 'production'
require 'rspec/core'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
spec.pattern = FileList['spec/**/*_spec.rb']
end
require 'rubocop/rake_task'
RuboCop::RakeTask.new
task default: [:rubocop, :spec]
end

+ 6
- 0
app.json View File

@ -0,0 +1,6 @@
{
"name": "Math bot for Slack",
"description": "Slack integration with math.",
"respository": "https://github.com/dblock/slack-mathbot",
"keywords": ["slack", "integration", "math"],
}

+ 11
- 0
app.rb View File

@ -0,0 +1,11 @@
require File.expand_path('../config/environment', __FILE__)
require 'sinatra/base'
module SlackMathbot
class Web < Sinatra::Base
get '/' do
'Math is good for you.'
end
end
end

+ 18
- 0
app/slack-mathbot.rb View File

@ -0,0 +1,18 @@
require 'slack-mathbot/version'
require 'slack-mathbot/about'
require 'slack-mathbot/config'
require 'slack-mathbot/hooks'
require 'slack-mathbot/commands'
require 'slack-mathbot/app'
module SlackMathbot
class << self
def configure
block_given? ? yield(Config) : Config
end
def config
Config
end
end
end

+ 7
- 0
app/slack-mathbot/about.rb View File

@ -0,0 +1,7 @@
module SlackMathbot
ABOUT = <<-ABOUT
#{SlackMathbot::VERSION}
https://github.com/dblock/slack-mathbot
https://twitter.com/dblockdotorg
ABOUT
end

+ 83
- 0
app/slack-mathbot/app.rb View File

@ -0,0 +1,83 @@
module SlackMathbot
class App
cattr_accessor :hooks
include SlackMathbot::Hooks::Hello
include SlackMathbot::Hooks::Message
def initialize
SlackMathbot.configure do |config|
config.token = ENV['SLACK_API_TOKEN'] || fail("Missing ENV['SLACK_API_TOKEN'].")
end
Slack.configure do |config|
config.token = SlackMathbot.config.token
end
end
def config
SlackMathbot.config
end
def self.instance
@instance ||= SlackMathbot::App.new
end
def run
auth!
start!
end
def stop!
client.stop
end
private
def logger
@logger ||= begin
$stdout.sync = true
Logger.new(STDOUT)
end
end
def start!
loop do
client.start
@client = nil
end
end
def client
@client ||= begin
client = Slack.realtime
hooks.each do |hook|
client.on hook do |data|
begin
send hook, data
rescue StandardError => e
logger.error e
begin
Slack.chat_postMessage(channel: data['channel'], text: e.message) if data.key?('channel')
rescue
# ignore
end
end
end
end
client
end
end
def auth!
auth = Slack.auth_test
SlackMathbot.configure do |config|
config.url = auth['url']
config.team = auth['team']
config.user = auth['user']
config.team_id = auth['team_id']
config.user_id = auth['user_id']
end
logger.info "Welcome '#{SlackMathbot.config.user}' to the '#{SlackMathbot.config.team}' team at #{SlackMathbot.config.url}."
end
end
end

+ 6
- 0
app/slack-mathbot/commands.rb View File

@ -0,0 +1,6 @@
require 'slack-mathbot/commands/base'
require 'slack-mathbot/commands/calculate'
require 'slack-mathbot/commands/about'
require 'slack-mathbot/commands/help'
require 'slack-mathbot/commands/hi'
require 'slack-mathbot/commands/unknown'

+ 9
- 0
app/slack-mathbot/commands/about.rb View File

@ -0,0 +1,9 @@
module SlackMathbot
module Commands
class Default < Base
def self.call(data, _command, _arguments)
send_message data.channel, SlackMathbot::ABOUT
end
end
end
end

+ 16
- 0
app/slack-mathbot/commands/base.rb View File

@ -0,0 +1,16 @@
module SlackMathbot
module Commands
class Base
def self.send_message(channel, text)
Slack.chat_postMessage(channel: channel, text: text)
end
def self.logger
@logger ||= begin
$stdout.sync = true
Logger.new(STDOUT)
end
end
end
end
end

+ 10
- 0
app/slack-mathbot/commands/calculate.rb View File

@ -0,0 +1,10 @@
module SlackMathbot
module Commands
class Calculate < Base
def self.call(data, _command, arguments)
result = Dentaku::Calculator.new.evaluate(arguments.join) || 'Got nothing.'
send_message data.channel, result.to_s
end
end
end
end

+ 9
- 0
app/slack-mathbot/commands/help.rb View File

@ -0,0 +1,9 @@
module SlackMathbot
module Commands
class Help < Base
def self.call(data, _command, _arguments)
send_message data.channel, 'See https://github.com/dblock/slack-mathbot, please.'
end
end
end
end

+ 9
- 0
app/slack-mathbot/commands/hi.rb View File

@ -0,0 +1,9 @@
module SlackMathbot
module Commands
class Hi < Base
def self.call(data, _command, _arguments)
send_message data.channel, "Hi <@#{data.user}>!"
end
end
end
end

+ 9
- 0
app/slack-mathbot/commands/unknown.rb View File

@ -0,0 +1,9 @@
module SlackMathbot
module Commands
class Unknown < Base
def self.call(data, _command, _arguments)
send_message data.channel, "Sorry <@#{data.user}>, I don't understand that command!"
end
end
end
end

+ 13
- 0
app/slack-mathbot/config.rb View File

@ -0,0 +1,13 @@
module SlackMathbot
module Config
extend self
attr_accessor :token
attr_accessor :url
attr_accessor :user
attr_accessor :user_id
attr_accessor :team
attr_accessor :team_id
attr_accessor :secret
end
end

+ 3
- 0
app/slack-mathbot/hooks.rb View File

@ -0,0 +1,3 @@
require 'slack-mathbot/hooks/base'
require 'slack-mathbot/hooks/hello'
require 'slack-mathbot/hooks/message'

+ 10
- 0
app/slack-mathbot/hooks/base.rb View File

@ -0,0 +1,10 @@
module SlackMathbot
module Hooks
module Base
def included(caller)
caller.hooks ||= []
caller.hooks << name.demodulize.underscore.to_sym
end
end
end
end

+ 11
- 0
app/slack-mathbot/hooks/hello.rb View File

@ -0,0 +1,11 @@
module SlackMathbot
module Hooks
module Hello
extend Base
def hello(_data)
logger.info "Successfully connected to #{SlackMathbot.config.url}."
end
end
end
end

+ 33
- 0
app/slack-mathbot/hooks/message.rb View File

@ -0,0 +1,33 @@
module SlackMathbot
module Hooks
module Message
extend Base
def message(data)
data = Hashie::Mash.new(data)
bot_name, command, arguments = parse_command(data.text)
return unless bot_name == SlackMathbot.config.user
klass = command_to_class(command || 'Default')
klass.call data, command, arguments
end
private
def parse_command(text)
return unless text
text = '= ' + text[1..text.length] if text[0] == '='
parts = text.split.reject(&:blank?)
if parts && parts[0] == '='
parts[0] = SlackMathbot.config.user
parts.insert 1, 'calculate'
end
[parts.first.downcase, parts[1].try(:downcase), parts[2..parts.length]] if parts && parts.any?
end
def command_to_class(command)
klass = "SlackMathbot::Commands::#{command.titleize}".constantize rescue nil
klass || SlackMathbot::Commands::Unknown
end
end
end
end

+ 3
- 0
app/slack-mathbot/version.rb View File

@ -0,0 +1,3 @@
module SlackMathbot
VERSION = '0.1.0'
end

+ 1
- 0
app/slack_mathbot.rb View File

@ -0,0 +1 @@
require 'slack-mathbot'

+ 7
- 0
config.ru View File

@ -0,0 +1,7 @@
require File.expand_path('../app', __FILE__)
Thread.new do
SlackMathbot::App.instance.run
end
run SlackMathbot::Web

+ 14
- 0
config/application.rb View File

@ -0,0 +1,14 @@
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'app'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'boot'
Bundler.require :default, ENV['RACK_ENV']
Dir[File.expand_path('../initializers', __FILE__) + '/**/*.rb'].each do |file|
require file
end
require File.expand_path('../application', __FILE__)
require 'slack_mathbot'

+ 5
- 0
config/boot.rb View File

@ -0,0 +1,5 @@
require 'rubygems'
require 'bundler/setup'
require 'logger'
require 'active_support'
require 'active_support/core_ext'

+ 3
- 0
config/environment.rb View File

@ -0,0 +1,3 @@
ENV['RACK_ENV'] ||= 'development'
require File.expand_path('../application', __FILE__)

+ 13
- 0
config/initializers/slack/request.rb View File

@ -0,0 +1,13 @@
module Slack
module Request
private
alias_method :_request, :request
def request(method, path, options)
response = _request(method, path, options)
fail response['error'] unless response['ok'] if response.is_a?(Hash)
response
end
end
end

BIN
screenshots/register-bot.png View File

Before After
Width: 997  |  Height: 519  |  Size: 57 KiB

BIN
screenshots/two-plus-two.gif View File

Before After
Width: 721  |  Height: 150  |  Size: 18 KiB

+ 103
- 0
spec/fixtures/slack/auth_test.yml View File

@ -0,0 +1,103 @@
---
http_interactions:
- request:
method: post
uri: https://slack.com/api/auth.test
body:
encoding: UTF-8
string: token=token
headers:
Accept:
- application/json; charset=utf-8
User-Agent:
- Slack Ruby Gem 1.1.1
Content-Type:
- application/x-www-form-urlencoded
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Access-Control-Allow-Origin:
- '*'
Cache-Control:
- private, no-cache, no-store, must-revalidate
Content-Type:
- application/json; charset=utf-8
Date:
- Tue, 28 Apr 2015 12:55:23 GMT
Expires:
- Mon, 26 Jul 1997 05:00:00 GMT
Pragma:
- no-cache
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
Vary:
- Accept-Encoding
X-Accepted-Oauth-Scopes:
- identify
X-Content-Type-Options:
- nosniff
X-Oauth-Scopes:
- identify,read,post,client
X-Xss-Protection:
- '0'
Content-Length:
- '128'
Connection:
- keep-alive
body:
encoding: UTF-8
string: '{"ok":true,"url":"https:\/\/math.slack.com\/","team":"calcteam","user":"calcuser","team_id":"TDEADBEEF","user_id":"UBAADFOOD"}'
http_version:
recorded_at: Tue, 28 Apr 2015 12:55:22 GMT
- request:
method: post
uri: https://slack.com/api/rtm.start
body:
encoding: UTF-8
string: token=token
headers:
Accept:
- application/json; charset=utf-8
User-Agent:
- Slack Ruby Gem 1.1.1
Content-Type:
- application/x-www-form-urlencoded
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Access-Control-Allow-Origin:
- '*'
Content-Type:
- application/json; charset=utf-8
Date:
- Tue, 28 Apr 2015 21:41:33 GMT
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Xss-Protection:
- '0'
Content-Length:
- '55'
Connection:
- keep-alive
body:
encoding: UTF-8
string: '{"ok":false,"error":"invalid_auth"}'
http_version:
recorded_at: Tue, 28 Apr 2015 21:41:33 GMT
recorded_with: VCR 2.9.3

+ 59
- 0
spec/fixtures/slack/user_info.yml View File

@ -0,0 +1,59 @@
---
http_interactions:
- request:
method: post
uri: https://slack.com/api/users.info
body:
encoding: UTF-8
string: token=token&user=user
headers:
Accept:
- application/json; charset=utf-8
User-Agent:
- Slack Ruby Gem 1.1.1
Content-Type:
- application/x-www-form-urlencoded
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
response:
status:
code: 200
message: OK
headers:
Access-Control-Allow-Origin:
- '*'
Cache-Control:
- private, no-cache, no-store, must-revalidate
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 29 Apr 2015 16:10:34 GMT
Expires:
- Mon, 26 Jul 1997 05:00:00 GMT
Pragma:
- no-cache
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains; preload
Vary:
- Accept-Encoding
X-Accepted-Oauth-Scopes:
- read
X-Content-Type-Options:
- nosniff
X-Oauth-Scopes:
- identify,read,post,client
X-Xss-Protection:
- '0'
Content-Length:
- '448'
Connection:
- keep-alive
body:
encoding: UTF-8
string: '{"ok":true,"user":{"id":"U007","name":"username","deleted":false,"status":null,"color":"9f69e7","real_name":"","tz":"America\/Indiana\/Indianapolis","tz_label":"Eastern
Daylight Time","tz_offset":-14400,"profile":{"real_name":"","real_name_normalized":"","email":"dblock@dblock.org","image_24":"https:\/\/secure.gravatar.com\/avatar\/3d925b45ac07ec0ae5bd04888f6c5b61.jpg?s=24&d=https%3A%2F%2Fslack.global.ssl.fastly.net%2F3654%2Fimg%2Favatars%2Fava_0015-24.png","image_32":"https:\/\/secure.gravatar.com\/avatar\/3d925b45ac07ec0ae5bd04888f6c5b61.jpg?s=32&d=https%3A%2F%2Fslack.global.ssl.fastly.net%2F3654%2Fimg%2Favatars%2Fava_0015-32.png","image_48":"https:\/\/secure.gravatar.com\/avatar\/3d925b45ac07ec0ae5bd04888f6c5b61.jpg?s=48&d=https%3A%2F%2Fslack.global.ssl.fastly.net%2F3654%2Fimg%2Favatars%2Fava_0015-48.png","image_72":"https:\/\/secure.gravatar.com\/avatar\/3d925b45ac07ec0ae5bd04888f6c5b61.jpg?s=72&d=https%3A%2F%2Fslack.global.ssl.fastly.net%2F3654%2Fimg%2Favatars%2Fava_0015-72.png","image_192":"https:\/\/secure.gravatar.com\/avatar\/3d925b45ac07ec0ae5bd04888f6c5b61.jpg?s=192&d=https%3A%2F%2Fslack.global.ssl.fastly.net%2F272a%2Fimg%2Favatars%2Fava_0015.png"},"is_admin":true,"is_owner":true,"is_primary_owner":true,"is_restricted":false,"is_ultra_restricted":false,"is_bot":false,"has_files":false}}'
http_version:
recorded_at: Wed, 29 Apr 2015 16:10:34 GMT

+ 32
- 0
spec/slack-mathbot/app_spec.rb View File

@ -0,0 +1,32 @@
require 'spec_helper'
describe SlackMathbot::App do
subject do
SlackMathbot::App.new
end
context 'not configured' do
before do
@slack_api_token = ENV.delete('SLACK_API_TOKEN')
end
after do
ENV['SLACK_API_TOKEN'] = @slack_api_token
end
it 'requires SLACK_API_TOKEN' do
expect { subject }.to raise_error RuntimeError, "Missing ENV['SLACK_API_TOKEN']."
end
end
context 'configured', vcr: { cassette_name: 'auth_test' } do
context 'run' do
before do
subject.send(:auth!)
end
it 'succeeds auth' do
expect(subject.config.url).to eq 'https://math.slack.com/'
expect(subject.config.team).to eq 'calcteam'
expect(subject.config.user).to eq 'calcuser'
expect(subject.config.team_id).to eq 'TDEADBEEF'
expect(subject.config.user_id).to eq 'UBAADFOOD'
end
end
end
end

+ 10
- 0
spec/slack-mathbot/commands/about_spec.rb View File

@ -0,0 +1,10 @@
require 'spec_helper'
describe SlackMathbot::Commands::Default do
it 'mathbot' do
expect(message: 'mathbot').to respond_with_slack_message(SlackMathbot::ABOUT)
end
it 'Mathbot' do
expect(message: 'Mathbot').to respond_with_slack_message(SlackMathbot::ABOUT)
end
end

+ 16
- 0
spec/slack-mathbot/commands/calculate_spec.rb View File

@ -0,0 +1,16 @@
require 'spec_helper'
describe SlackMathbot::Commands::Calculate, vcr: { cassette_name: 'user_info' } do
it 'adds two numbers' do
expect(message: 'mathbot calculate 2+2', channel: 'channel').to respond_with_slack_message('4')
end
it 'adds two numbers via =' do
expect(message: '= 2+2', channel: 'channel').to respond_with_slack_message('4')
end
it 'adds two numbers via = without a space' do
expect(message: '=2+2', channel: 'channel').to respond_with_slack_message('4')
end
it 'sends something without an answer' do
expect(message: 'mathbot calculate pi', channel: 'channel').to respond_with_slack_message('Got nothing.')
end
end

+ 7
- 0
spec/slack-mathbot/commands/help_spec.rb View File

@ -0,0 +1,7 @@
require 'spec_helper'
describe SlackMathbot::Commands::Help do
it 'help' do
expect(message: 'mathbot help').to respond_with_slack_message('See https://github.com/dblock/slack-mathbot, please.')
end
end

+ 7
- 0
spec/slack-mathbot/commands/hi_spec.rb View File

@ -0,0 +1,7 @@
require 'spec_helper'
describe SlackMathbot::Commands::Hi do
it 'says hi' do
expect(message: 'mathbot hi').to respond_with_slack_message('Hi <@user>!')
end
end

+ 11
- 0
spec/slack-mathbot/commands/unknown_spec.rb View File

@ -0,0 +1,11 @@
require 'spec_helper'
describe SlackMathbot::Commands::Unknown, vcr: { cassette_name: 'user_info' } do
it 'invalid command' do
expect(message: 'mathbot foobar').to respond_with_slack_message("Sorry <@user>, I don't understand that command!")
end
it 'does not respond to sad face' do
expect(SlackMathbot::Commands::Base).to_not receive(:send_message)
SlackMathbot::App.new.send(:message, text: ':((')
end
end

+ 7
- 0
spec/slack-mathbot/version_spec.rb View File

@ -0,0 +1,7 @@
require 'spec_helper'
describe SlackMathbot do
it 'has a version' do
expect(SlackMathbot::VERSION).to_not be nil
end
end

+ 12
- 0
spec/spec_helper.rb View File

@ -0,0 +1,12 @@
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
require 'rubygems'
require 'rspec'
require 'rack/test'
require 'config/environment'
require 'slack-mathbot'
Dir[File.join(File.dirname(__FILE__), 'support', '**/*.rb')].each do |file|
require file
end

+ 30
- 0
spec/support/slack-mathbot/respond_with_error.rb View File

@ -0,0 +1,30 @@
require 'rspec/expectations'
RSpec::Matchers.define :respond_with_error do |expected|
match do |actual|
channel, user, message = parse(actual)
app = SlackMathbot::App.new
SlackMathbot.config.user = 'mathbot'
begin
expect do
app.send(:message, text: message, channel: channel, user: user)
end.to raise_error ArgumentError, expected
rescue RSpec::Expectations::ExpectationNotMetError => e
@error_message = e.message
raise e
end
true
end
failure_message do |actual|
_, _, message = parse(actual)
@error_message || "expected for '#{message}' to fail with '#{expected}'"
end
private
def parse(actual)
actual = { message: actual } unless actual.is_a?(Hash)
[actual[:channel] || 'channel', actual[:user] || 'user', actual[:message]]
end
end

+ 19
- 0
spec/support/slack-mathbot/respond_with_slack_message.rb View File

@ -0,0 +1,19 @@
require 'rspec/expectations'
RSpec::Matchers.define :respond_with_slack_message do |expected|
match do |actual|
channel, user, message = parse(actual)
app = SlackMathbot::App.new
SlackMathbot.config.user = 'mathbot'
expect(SlackMathbot::Commands::Base).to receive(:send_message).with(channel, expected)
app.send(:message, text: message, channel: channel, user: user)
true
end
private
def parse(actual)
actual = { message: actual } unless actual.is_a?(Hash)
[actual[:channel] || 'channel', actual[:user] || 'user', actual[:message]]
end
end

+ 5
- 0
spec/support/slack_api_key.rb View File

@ -0,0 +1,5 @@
RSpec.configure do |config|
config.before :all do
ENV['SLACK_API_TOKEN'] ||= 'test'
end
end

+ 4
- 0
spec/support/slack_calculator.rb View File

@ -0,0 +1,4 @@
SlackMathbot.configure do |config|
config.token = 'testtoken'
config.user = 'mathbot'
end

+ 8
- 0
spec/support/vcr.rb View File

@ -0,0 +1,8 @@
require 'vcr'
VCR.configure do |config|
config.cassette_library_dir = 'spec/fixtures/slack'
config.hook_into :webmock
# config.default_cassette_options = { record: :new_episodes }
config.configure_rspec_metadata!
end

Loading…
Cancel
Save