Skip to content

Commit

Permalink
Added support for generic routes via match, closes #5.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Jul 19, 2015
1 parent 1288937 commit 8931a6e
Show file tree
Hide file tree
Showing 23 changed files with 123 additions and 150 deletions.
10 changes: 5 additions & 5 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This configuration was generated by `rubocop --auto-gen-config`
# on 2015-07-19 08:58:31 -0400 using RuboCop version 0.32.1.
# on 2015-07-19 12:16:52 -0400 using RuboCop version 0.32.1.
# 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
Expand All @@ -13,19 +13,19 @@ Lint/HandleExceptions:
Lint/UselessAccessModifier:
Enabled: false

# Offense count: 1
# Offense count: 2
Metrics/AbcSize:
Max: 21

# Offense count: 28
# Offense count: 37
# Configuration parameters: AllowURI, URISchemes.
Metrics/LineLength:
Max: 142

# Offense count: 1
# Offense count: 2
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 17
Max: 18

# Offense count: 15
Style/Documentation:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### 0.3.0 (Next)

* [#5](https://github.com/dblock/slack-ruby-bot/issues/5): Added support for free-formed routes via `match` - [@dblock](https://github.com/dblock).
* [#6](https://github.com/dblock/slack-ruby-bot/issues/6): Commands and operators take blocks - [@dblock](https://github.com/dblock).
* [#4](https://github.com/dblock/slack-ruby-bot/issues/4): Messages are posted with `as_user: true` by default - [@dblock](https://github.com/dblock).
* Your contribution here.
Expand Down
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module PongBot
end

class Ping < SlackRubyBot::Commands::Base
command 'ping' do |data, command, arguments|
command 'ping' do |data, _match|
send_message data.channel, 'pong'
end
end
Expand Down Expand Up @@ -60,7 +60,7 @@ Bots are addressed by name and respond to commands and operators. By default a c
class Phone < SlackRubyBot::Commands::Base
command 'call'

def self.call(data, command, arguments)
def self.call(data, _match)
send_message data.channel, 'called'
end
end
Expand All @@ -73,7 +73,7 @@ class Phone < SlackRubyBot::Commands::Base
command 'call'
command '呼び出し'

def self.call(data, command, arguments)
def self.call(data, _match)
send_message data.channel, 'called'
end
end
Expand All @@ -83,22 +83,40 @@ You can combine multiple commands and use a block to implement them.

```ruby
class Phone < SlackRubyBot::Commands::Base
command 'call', '呼び出し' do
command 'call', '呼び出し' do |data, _match|
send_message data.channel, 'called'
end
end
```

Command match data includes `match['bot']`, `match['command']` and `match['expression']`. The `bot` match always checks against the `SlackRubyBot::Config.user` setting.

Operators are 1-letter long and are similar to commands. They don't require addressing a bot nor separating an operator from its arguments. The following class responds to `=2+2`.

```ruby
class Calculator < SlackRubyBot::Commands::Base
operator '=' do
operator '=' do |_data, _match|
# implementation detail
end
end
```

Operator match data includes `match['operator']` and `match['expression']`. The `bot` match always checks against the `SlackRubyBot::Config.user` setting.

### Generic Routing

Commands and operators are generic versions of bot routes. You can respond to just about anything by defining a custom route.

```ruby
class Weather < SlackRubyBot::Commands::Base
match /^How is the weather in (<?location>\w*)\?$/ do |data, match|
send_message data.channel, "The weather in #{match[:location]} is nice."
end
end
```

![](screenshots/weather.gif)

### Built-In Commands

Slack-ruby-bot comes with several built-in commands. You can re-define built-in commands, normally, as described above.
Expand Down
2 changes: 1 addition & 1 deletion TUTORIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Create a folder called `slack-mathbot/commands` and inside of it create `calcula
module SlackMathbot
module Commands
class Calculate < SlackRubyBot::Commands::Base
def self.call(data, command, arguments)
command 'calculate' do |data, _match|
send_message data.channel, '4'
end
end
Expand Down
7 changes: 4 additions & 3 deletions examples/minimal/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
PATH
remote: ../..
specs:
slack-ruby-bot (0.2.0)
slack-ruby-bot (0.3.0)
activesupport
giphy (~> 2.0.2)
hashie
slack-api (~> 1.1.6)
websocket-driver (~> 0.5.4)

GEM
remote: http://rubygems.org/
Expand All @@ -20,7 +21,7 @@ GEM
eventmachine (1.0.7)
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.9.1)
faraday_middleware (0.9.2)
faraday (>= 0.7.4, < 0.10)
faraday_middleware-parse_oj (0.3.0)
faraday (~> 0.9.0)
Expand All @@ -40,7 +41,7 @@ GEM
launchy (2.4.3)
addressable (~> 2.3)
minitest (5.7.0)
multi_json (1.11.1)
multi_json (1.11.2)
multipart-post (2.0.0)
oj (2.12.9)
slack-api (1.1.6)
Expand Down
2 changes: 1 addition & 1 deletion examples/minimal/pongbot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class App < SlackRubyBot::App
end

class Ping < SlackRubyBot::Commands::Base
def self.call(data, _command, _arguments)
def self.call(data, _match)
send_message data.channel, 'pong'
end
end
Expand Down
3 changes: 3 additions & 0 deletions examples/weather/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source 'http://rubygems.org'

gem 'slack-ruby-bot', path: '../..'
14 changes: 14 additions & 0 deletions examples/weather/weatherbot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'slack-ruby-bot'

module WeatherBot
class App < SlackRubyBot::App
end

class Weather < SlackRubyBot::Commands::Base
match(/^How is the weather in (?<location>\w*)\?$/i) do |data, match|
send_message data.channel, "The weather in #{match[:location]} is nice."
end
end
end

WeatherBot::App.instance.run
5 changes: 3 additions & 2 deletions lib/slack-ruby-bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
require 'slack-ruby-bot/about'
require 'slack-ruby-bot/config'
require 'slack-ruby-bot/hooks'
require 'slack-ruby-bot/commands'
require 'slack-ruby-bot/app'

module SlackRubyBot
class << self
Expand All @@ -18,3 +16,6 @@ def config
end
end
end

require 'slack-ruby-bot/commands'
require 'slack-ruby-bot/app'
4 changes: 2 additions & 2 deletions lib/slack-ruby-bot/commands/about.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module SlackRubyBot
module Commands
class Default < Base
command 'default'
command 'about'
match(/^(?<bot>\w*)$/)

def self.call(data, _command, _arguments)
def self.call(data, _match)
send_message_with_gif data.channel, SlackRubyBot::ABOUT, 'selfie'
end
end
Expand Down
54 changes: 31 additions & 23 deletions lib/slack-ruby-bot/commands/base.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
module SlackRubyBot
module Commands
class Base
class_attribute :operators
class_attribute :commands
class_attribute :routes

def self.send_message(channel, text, options = { as_user: true })
if text && text.length > 0
Expand Down Expand Up @@ -30,49 +29,58 @@ def self.logger
end
end

def self.responds_to_command?(command)
commands ? commands.keys.include?(command) : command == default_command_name
end

def self.default_command_name
name && name.split(':').last.downcase
end

def self.responds_to_operator?(operator)
operators && operators.keys.include?(operator)
end

def self.operator(*values, &block)
self.operators ||= {}
values.each do |value|
self.operators[value] = block
match Regexp.new("^[\s]*(?<operator>\\#{value})(?<expression>.*)$", Regexp::IGNORECASE), &block
end
end

def self.command(*values, &block)
self.commands ||= {}
values.each do |value|
self.commands[value] = block
match Regexp.new("^[\s]*(?<bot>\\w*)[\\s]+(?<command>#{value})[\\s]*(?<expression>.*)$", Regexp::IGNORECASE), &block
end
end

def self.invoke(data, command, arguments)
method = self.commands[command] if self.commands
method ||= self.operators[command] if self.operators
if method
method.call(data, command, arguments)
elsif self.respond_to?(:call)
send :call, data, command, arguments
else
fail NotImplementedError, command
def self.invoke(data)
self.finalize_routes!
expression = data.text
called = false
routes.each_pair do |route, method|
match = route.match(expression)
next unless match
next if match.names.include?('bot') && match['bot'].downcase != SlackRubyBot.config.user
called = true
if method
method.call(data, match)
elsif self.respond_to?(:call)
send(:call, data, match)
else
fail NotImplementedError, data.text
end
break
end
called
end

def self.match(match, &block)
self.routes ||= {}
self.routes[match] = block
end

private

def self.chat_postMessage(message)
Slack.chat_postMessage(message)
end

def self.finalize_routes!
return if self.routes && self.routes.any?
command default_command_name
end
end
end
end
2 changes: 1 addition & 1 deletion lib/slack-ruby-bot/commands/help.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module SlackRubyBot
module Commands
class Help < Base
def self.call(data, _command, _arguments)
def self.call(data, _match)
send_message_with_gif data.channel, 'See https://github.com/dblock/slack-ruby-bot, please.', 'help'
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/slack-ruby-bot/commands/hi.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module SlackRubyBot
module Commands
class Hi < Base
def self.call(data, _command, _arguments)
def self.call(data, _match)
send_message_with_gif data.channel, "Hi <@#{data.user}>!", 'hi'
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/slack-ruby-bot/commands/unknown.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module SlackRubyBot
module Commands
class Unknown < Base
def self.call(data, _command, _arguments)
match(/^(?<bot>\w*)[\s]*(?<expression>.*)$/)

def self.call(data, _match)
send_message_with_gif data.channel, "Sorry <@#{data.user}>, I don't understand that command!", 'idiot'
end
end
Expand Down
Loading

0 comments on commit 8931a6e

Please sign in to comment.