@ -0,0 +1 @@ | |||
.env |
@ -0,0 +1,2 @@ | |||
--format documentation | |||
--color |
@ -0,0 +1,6 @@ | |||
AllCops: | |||
Exclude: | |||
- vendor/**/* | |||
- bin/**/* | |||
inherit_from: .rubocop_todo.yml |
@ -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 |
@ -0,0 +1,3 @@ | |||
rvm: | |||
- 2.1.6 | |||
@ -0,0 +1,3 @@ | |||
### 0.1.0 (Next) | |||
* Initial public release - [@dblock](https://github.com/dblock). |
@ -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. |
@ -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. |
@ -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 |
@ -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 |
@ -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. |
@ -0,0 +1 @@ | |||
web: bundle exec puma -p $PORT |
@ -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). |
@ -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 |
@ -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"], | |||
} |
@ -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 |
@ -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 |
@ -0,0 +1,7 @@ | |||
module SlackMathbot | |||
ABOUT = <<-ABOUT | |||
#{SlackMathbot::VERSION} | |||
https://github.com/dblock/slack-mathbot | |||
https://twitter.com/dblockdotorg | |||
ABOUT | |||
end |
@ -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 |
@ -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' |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -0,0 +1,3 @@ | |||
require 'slack-mathbot/hooks/base' | |||
require 'slack-mathbot/hooks/hello' | |||
require 'slack-mathbot/hooks/message' |
@ -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 |
@ -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 |
@ -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 |
@ -0,0 +1,3 @@ | |||
module SlackMathbot | |||
VERSION = '0.1.0' | |||
end |
@ -0,0 +1 @@ | |||
require 'slack-mathbot' |
@ -0,0 +1,7 @@ | |||
require File.expand_path('../app', __FILE__) | |||
Thread.new do | |||
SlackMathbot::App.instance.run | |||
end | |||
run SlackMathbot::Web |
@ -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' |
@ -0,0 +1,5 @@ | |||
require 'rubygems' | |||
require 'bundler/setup' | |||
require 'logger' | |||
require 'active_support' | |||
require 'active_support/core_ext' |
@ -0,0 +1,3 @@ | |||
ENV['RACK_ENV'] ||= 'development' | |||
require File.expand_path('../application', __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 |
@ -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 |
@ -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 | |||
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -0,0 +1,7 @@ | |||
require 'spec_helper' | |||
describe SlackMathbot do | |||
it 'has a version' do | |||
expect(SlackMathbot::VERSION).to_not be nil | |||
end | |||
end |
@ -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 |
@ -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 |
@ -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 |
@ -0,0 +1,5 @@ | |||
RSpec.configure do |config| | |||
config.before :all do | |||
ENV['SLACK_API_TOKEN'] ||= 'test' | |||
end | |||
end |
@ -0,0 +1,4 @@ | |||
SlackMathbot.configure do |config| | |||
config.token = 'testtoken' | |||
config.user = 'mathbot' | |||
end |
@ -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 |