class Slackbotsy::Bot

Attributes

api[RW]
last_description[RW]
listeners[RW]

Public Class Methods

new(options, &block) click to toggle source
# File lib/slackbotsy/bot.rb, line 12
def initialize(options, &block)
  @options = options
  @listeners = []
  @options['outgoing_token'] = parse_outgoing_tokens(@options['outgoing_token'])
  setup_incoming_webhook                # http connection for async replies
  setup_web_api                         # setup slack Web API
  instance_eval(&block) if block_given? # run any hear statements in block
end

Public Instance Methods

attach(ary, options = {}) click to toggle source

simple wrapper on post to send attachment(s)

# File lib/slackbotsy/bot.rb, line 69
def attach(ary, options = {})
  attachments = ary.is_a?(Array) ? ary : [ ary ] #force first arg to array
  post({ attachments: attachments }.merge(options))
end
desc(command, description = nil) click to toggle source

record a description of the next hear block, for use in help

# File lib/slackbotsy/bot.rb, line 110
def desc(command, description = nil)
  @last_desc = [ command, description ]
end
eval_scripts(*files) click to toggle source

pass list of files containing hear statements, to be opened and evaled

# File lib/slackbotsy/bot.rb, line 121
def eval_scripts(*files)
  files.flatten.each do |file|
    self.instance_eval(File.open(file).read)
  end
end
get_responses(msg, text) click to toggle source

run on msg all hear blocks matching text

# File lib/slackbotsy/bot.rb, line 156
def get_responses(msg, text)
  message = Slackbotsy::Message.new(self, msg)
  @listeners.map do |listener|
    text.match(listener.regex) do |mdata|
     begin
        message.instance_exec(mdata, *mdata[1..-1], &listener.proc)
      rescue => err # keep running even with a broken script, but report the error
        err
      end
    end
  end
end
handle_item(msg) click to toggle source

alias for backward compatibility

# File lib/slackbotsy/bot.rb, line 141
def handle_item(msg)
  handle_outgoing_webhook(msg)
end
handle_outgoing_webhook(msg) click to toggle source

check message and run blocks for any matches

# File lib/slackbotsy/bot.rb, line 128
def handle_outgoing_webhook(msg)
  return nil unless @options['outgoing_token'].include?(msg[:token]) # ensure messages are for us from slack
  return nil if msg[:user_name] == 'slackbot'  # do not reply to self
  return nil unless msg[:text].is_a?(String) # skip empty messages

  responses = get_responses(msg, msg[:text].strip)

  if responses
    { text: responses.compact.join("\n") }.to_json # webhook responses are json
  end
end
handle_slash_command(msg) click to toggle source
# File lib/slackbotsy/bot.rb, line 145
def handle_slash_command(msg)
  return nil unless @options['slash_token'].include?(msg[:token])

  responses = get_responses(msg, "#{msg[:command]} #{msg[:text]}".strip)

  if responses
    responses.join("\n") # plain text responses
  end
end
hear(regex, &block) click to toggle source

add regex to things to hear

# File lib/slackbotsy/bot.rb, line 115
def hear(regex, &block)
  @listeners << OpenStruct.new(regex: regex, desc: @last_desc, proc: block)
  @last_desc = nil
end
parse_outgoing_tokens(tokens) click to toggle source

use set of tokens for (more or less) O(1) lookup on multiple channels

# File lib/slackbotsy/bot.rb, line 22
def parse_outgoing_tokens(tokens)
  case tokens
  when NilClass
    []
  when String
    tokens.split(/[,\s]+/)
  when Array
    tokens
  end.to_set
end
post(options) click to toggle source

raw post of hash to slack webhook

# File lib/slackbotsy/bot.rb, line 51
def post(options)
  payload = {
    username: @options['name'],
    channel:  @options['channel']
  }.merge(options)
  payload[:channel] = payload[:channel].gsub(/^#?/, '#') #slack api needs leading # on channel
  request = Net::HTTP::Post.new(@uri.request_uri)
  request.set_form_data(payload: payload.to_json)
  @http.request(request)
  return nil # so as not to trigger text in outgoing webhook reply
end
post_message(text, options = {}) click to toggle source

simple wrapper on api.post_message (which calls chat.postMessage)

# File lib/slackbotsy/bot.rb, line 75
def post_message(text, options = {})
  payload = {
    username: @options['name'],
    channel:  @options['channel'],
    text:     text,
    as_user:  true
  }.merge(options)

  unless direct_message?(payload[:channel])
    payload[:channel] = enforce_leading_hash(payload[:channel])
    @api.join(payload[:channel])
  end

  @api.post_message(payload)
  return nil # be quiet in webhook reply
end
say(text, options = {}) click to toggle source

simple wrapper on post to send text

# File lib/slackbotsy/bot.rb, line 64
def say(text, options = {})
  post({ text: text }.merge(options))
end
setup_incoming_webhook() click to toggle source

setup http connection for sending async incoming webhook messages to slack

# File lib/slackbotsy/bot.rb, line 34
def setup_incoming_webhook
  ## incoming_webhook will be used if provided, otherwise fallback to old-style url with team and token
  url = @options.fetch('incoming_webhook', false) || "https://#{@options['team']}.slack.com/services/hooks/incoming-webhook?token=#{@options['incoming_token']}"
  @uri  = URI.parse(url)
  @http = Net::HTTP.new(@uri.host, @uri.port)
  @http.use_ssl = true
  @http.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
setup_web_api() click to toggle source

use api_token to setup Web API authentication

# File lib/slackbotsy/bot.rb, line 44
def setup_web_api
  if @options['api_token']
    @api = Api.new(@options['api_token'])
  end
end
upload(options) click to toggle source

simple wrapper on api.upload (which calls files.upload) pass ‘channel’ as a csv list of channel names, otherwise same args as files.upload

# File lib/slackbotsy/bot.rb, line 94
def upload(options)
  payload = options
  channels = @api.channels # list of channel objects
  payload[:channels] ||= (options.fetch(:channel, @options['channel'])).split(/[\s,]+/).map do |name|
    channels.find { |c| name.match(/^#?#{c['name']}$/) }.fetch('id') # convert channel id to name
  end.join(',')
  @api.upload(payload)
  return nil # be quiet in webhook reply
end
users() click to toggle source

simple wrapper on api.users (which calls users.list)

# File lib/slackbotsy/bot.rb, line 105
def users
  @api.users
end

Private Instance Methods

direct_message?(channel) click to toggle source
# File lib/slackbotsy/bot.rb, line 176
def direct_message?(channel)
  channel.start_with?('@')
end
enforce_leading_hash(channel) click to toggle source
# File lib/slackbotsy/bot.rb, line 171
def enforce_leading_hash(channel)
  # chat.postMessage needs leading # on channel
  channel.gsub(/^#?/, '#')
end