class Slackify::Router

In charge of routing a message to its proper handler

Public Class Methods

all_commands() click to toggle source

List all available commands

# File lib/slackify/router.rb, line 8
def all_commands
  Slackify.configuration.handlers.collect(&:commands).flatten
end
call_command(message, params) click to toggle source

Call command based on message string

# File lib/slackify/router.rb, line 22
def call_command(message, params)
  command = matching_command(message)
  if command.nil?
    return unless Slackify.configuration.unhandled_handler

    Slackify.configuration.unhandled_handler.unhandled(params)
  else
    new_params = params.merge( command_arguments: extract_arguments(message, command) )

    command.handler.call(new_params)
  end
end
extract_arguments(message, command) click to toggle source
# File lib/slackify/router.rb, line 35
def extract_arguments(message, command)
  if command.regex
    command.regex.match(message).named_captures
  else
    raw_arguments = message.sub(/^#{command.base_command}/, '').strip
    spec = {}
    command.parameters.each do |parameter|
      spec[parameter.keys[0].to_sym] = { type: parameter.values[0].to_sym }
    end
    parse_by_spec(spec, raw_arguments)
  end
end
matching_command(message) click to toggle source

Find the matching command based on the message string

# File lib/slackify/router.rb, line 13
def matching_command(message)
  all_commands.each do |command|
    return command if command.regex.present? && command.regex.match?(message)
    return command if command.base_command.present? && message.start_with?(command.base_command)
  end
  nil
end
parse_by_spec(spec, raw_arguments) click to toggle source
# File lib/slackify/router.rb, line 48
def parse_by_spec(spec, raw_arguments)
  processed_args = {}

  s = StringScanner.new(raw_arguments)
  until s.eos?
    # get the key, remove '=' and extra whitespace
    current_key = s.scan_until(/=/)
    break if current_key.nil?

    current_key = current_key[0..-2].strip

    # grab value accounting for any quotes
    terminating_string = case s.peek(1)
                         when "'"
                           s.skip(/'/)
                           /'/
                         when '"'
                           s.skip(/"/)
                           /"/
                         else
                           / /
                         end
    processed_args[current_key.to_sym] = if s.exist?(terminating_string)
                                           # grab everything before the next instance of the terminating character
                                           s.scan_until(terminating_string)[0..-2]
                                         else
                                           # this is probably wrong unless we were expecting a space, but hit eos
                                           s.rest
                                         end
  end

  # only pass on expected parameters for now.
  processed_spec = {}
  spec.each do |key, value|
    # coerce to the expected type
    type = value.fetch(:type, 'string')
    processed_spec[key] = case type
                          when :int
                            processed_args[key].to_i
                          when :float
                            processed_args[key].to_f
                          when :boolean
                            ActiveModel::Type::Boolean.new.cast(processed_args[key])
                          when :string
                            processed_args[key]
                          else
                            Object.const_get(type).new(processed_args[key]).parse
                          end
  end

  processed_spec
end