Class: Slackify::Router

Inherits:
Object
  • Object
show all
Defined in:
lib/slackify/router.rb

Overview

In charge of routing a message to its proper handler

Constant Summary collapse

MATCHING_QUOTES =
{
  "'": "'",
  '"': '"',
  '': "",
}.freeze

Class Method Summary collapse

Class Method Details

.all_commandsObject

List all available commands



14
15
16
# File 'lib/slackify/router.rb', line 14

def all_commands
  Slackify.configuration.handlers.collect(&:commands).flatten
end

.call_command(message, params) ⇒ Object

Call command based on message string



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/slackify/router.rb', line 28

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) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/slackify/router.rb', line 41

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) ⇒ Object

Find the matching command based on the message string



19
20
21
22
23
24
25
# File 'lib/slackify/router.rb', line 19

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) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/slackify/router.rb', line 54

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
    next_char = s.getch
    terminating_string = if (end_quote = MATCHING_QUOTES[next_char.to_sym])
                           /#{end_quote}/
                         else
                           s.unscan
                           / /
                         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