A Ruby gem that makes processing Slack slash commands a breeze.
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin
commands
lib
spec
.gitignore
.rspec
.travis.yml
Gemfile
README.md
Rakefile
cksh_commander.gemspec

README.md

🌠 Sla[CK] Sla[SH] Commander

Build Status License

CKSHCommander is a Ruby gem that simplifies the task of processing Slack slash commands. It provides a class-based convention for authoring command handlers, and it supports basic subcommands and arguments. Check out the cksh_command_api repository to see a dead simple Sinatra API that comes bootstrapped with everything you need to process Slack slash commands using this gem.

Installation

You can install cksh_commander via RubyGems. In your Gemfile:

gem 'cksh_commander'

Or from a command line:

gem install cksh_commander

Usage

Getting Started

Defining a custom command is easy. First, create a commands/ directory and tell CKSHCommander where it can find your commands. Let's say we've created a commands/ directory at the root of our project. Our configuration is as follows:

# app.rb

require 'cksh_commander'

CKSHCommander.configure do |c|
  c.commands_path = File.expand_path("../commands", __FILE__)
end

Now, let's assume that we've set up an /example Slack command. We want to create a directory-based container for everything that our command might interact with. (For example, we may wish to log some command-specific data in a text file.) All that we have to do is to create a directory under our commands/ directory that matches the name of the slash command. In this case:

root/
  app.rb
  commands/
    example/
      command.rb
  ...

The last step is to create our custom command class. We name this class Command to abide by the convention. We define our class as follows. Note that the class must inherit from CKSHCommander::Command, and it should reside within a module that shares its name with the command.

# commands/example/command.rb

require "cksh_commander"

module Example
  class Command < CKSHCommander::Command
    set token: "gIkuvaNzQIHg97ATvDxqgjtO"

    # Subcommand with no arguments
    # SLACK: /example test0
    desc "test0", "Subcommand 0 description."
    def test0
      set_response_text("Subcommand: test0")
    end

    # Subcommand with one argument
    # SLACK: /example test1 text
    desc "test1 [TEXT]", "Subcommand 1 description."
    def test1(text)
      set_response_text("Subcommand: test1; Text: #{text}")
    end

    # No subcommand with one argument
    # SLACK: /example text
    desc "[TEXT]", "Root command description."
    def ___(text)
      set_response_text("Root command; Text: #{text}")
    end
  end
end

Command API

We set our slash command authentication token at the class level, and define methods for processing subcommands. Attachments (which take the form of a hash) can be added using add_response_attachment(attachment). You can also set the response to 'in_channel' at the method level with respond_in_channel!.

We can access the Slack payload data via the data reader.

data.token          #=> "gIkuvaNzQIHg97ATvDxqgjtO"
data.team_id        #=> "T0001"
data.team_domain    #=> "example"
data.channel_id     #=> "C2147483705"
data.channel_name   #=> "test"
data.user_id        #=> "U2147483697"
data.user_name      #=> "Randy"
data.command        #=> "/test"
data.text           #=> "subcommand"
data.response_url   #=> "https://hooks.slack.com/commands/1234/5678"

Similar to Thor, we are able to document our command's API with the class-level desc method—as is shown in the example above. CKSHCommander provides a help subcommand out of the box, and this will echo the documentation back to the Slack user.

/example test0         # Subcommand 0 description.
/example test1 [TEXT]  # Subcommand 1 description.
/example [TEXT]        # Root command description.

Use authorize to whitelist the user IDs of Slack users whom you've authorized to perform a subcommand. An unauthorized user who tries to use this subcommand will receive the response, "You are unauthorized to use this subcommand!" You can find the IDs of Slack users on your team using Slack's REST API. Note that authorization is not performed unless authorize is used explicitly.

...
desc "privatecmd", "A private subcommand."
def privatecmd
  authorize(%w[U2147483697])
  set_response_text("You are authorized!")
end
...

If you need to debug a subcommand and forward a caught exception to your Slack client, you can use debug! at the top of your subcommand's method body. Otherwise, exceptions at the subcommand level will result in the set error message text being returned to the client. Using debug! like this allows you to isolate testing to a single subcommand without disrupting all usage of the slash command.

...
set error_message: "Hm. Something went wrong!"

def subcommand
  debug!
  undefined_method #=> NameError
  set_response_text("Never evaluated...")
end
...

Running a Command

To run a command, we use CKSHCommander::Runner. In the example below, we've created a simple Sinatra app to illustrate its usage with the standard Slack slash command payload.

# app.rb

require "sinatra"
require "json"
require "cksh_commander"

CKSHCommander.configure do |c|
  c.commands_path = File.expand_path("../commands", __FILE__)
end

post "/" do
  content_type :json

  command = params["command"][1..-1]
  response = CKSHCommander::Runner.run(command, params)
  JSON.dump(response.serialize)
end

Examples

Check out (and/or use) example commands provided by the community. Want to contribute a command? Great! Add your command to the commands/ directory and open a pull request! The implementations below provide convenient reference points.

command description
jira Display JIRA issue details in a Slack channel or message.
lunch State or revoke your intention to attend the weekly lunch gathering.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/openarcllc/cksh_commander.