Class: Discordrb::Commands::CommandBot

Inherits:
Bot
  • Object
show all
Defined in:
lib/discordrb/commands/command_bot.rb

Overview

Bot that supports commands and command chains

Instance Attribute Summary collapse

Attributes inherited from Bot

#bot_user, #event_threads, #name, #profile, #servers, #should_parse_self, #users, #voice

Instance Method Summary collapse

Methods inherited from Bot

#add_await, #add_handler, #await, #channel, #channel_create, #channel_delete, #channel_update, #create_server, #debug, #debug=, #delete_invite, #disconnected, #find, #find_user, #game=, #handler_class, #invite, #join, #log_exception, #member_join, #member_leave, #member_update, #mention, #message, #message_delete, #message_edit, #parse_mention, #playing, #pm, #presence, #private_channel, #ready, #remove_handler, #resolve_invite_code, #run, #run_async, #send_file, #send_message, #server, #server_create, #server_delete, #server_update, #stop, #suppress_ready_debug, #sync, #token, #typing, #user, #user_ban, #user_unban, #voice_connect, #voice_state_update

Methods included from Events

matches_all

Constructor Details

#initialize(email, password, prefix, attributes = {}, debug = false) ⇒ CommandBot

Returns a new instance of CommandBot.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
# File 'lib/discordrb/commands/command_bot.rb', line 13

def initialize(email, password, prefix, attributes = {}, debug = false)
  super(email, password, debug)
  @prefix = prefix
  @commands = {}
  @attributes = {
    # Whether advanced functionality such as command chains are enabled
    advanced_functionality: attributes[:advanced_functionality].nil? ? true : attributes[:advanced_functionality],

    # The name of the help command (that displays information to other commands). Nil if none should exist
    help_command: attributes[:help_command] || :help,

    # The message to display for when a command doesn't exist, %command% to get the command name in question and nil for no message
    # No default value here because it may not be desired behaviour
    command_doesnt_exist_message: attributes[:command_doesnt_exist_message],

    # All of the following need to be one character
    # String to designate previous result in command chain
    previous: attributes[:previous] || '~',

    # Command chain delimiter
    chain_delimiter: attributes[:chain_delimiter] || '>',

    # Chain argument delimiter
    chain_args_delim: attributes[:chain_args_delim] || ':',

    # Sub-chain starting character
    sub_chain_start: attributes[:sub_chain_start] || '[',

    # Sub-chain ending character
    sub_chain_end: attributes[:sub_chain_end] || ']',

    # Quoted mode starting character
    quote_start: attributes[:quote_start] || '"',

    # Quoted mode ending character
    quote_end: attributes[:quote_end] || '"'
  }

  @permissions = {
    roles: {},
    users: {}
  }

  return unless @attributes[:help_command]
  command(@attributes[:help_command], max_args: 1, description: 'Shows a list of all the commands available or displays help for a specific command.', usage: 'help [command name]') do |event, command_name|
    if command_name
      command = @commands[command_name.to_sym]
      return "The command `#{command_name}` does not exist!" unless command
      desc = command.attributes[:description] || '*No description available*'
      usage = command.attributes[:usage]
      result = "**`#{command_name}`**: #{desc}"
      result << "\nUsage: `#{usage}`" if usage
    else
      available_commands = @commands.values.reject { |c| !c.attributes[:help_available] }
      case available_commands.length
      when 0..5
        available_commands.reduce "**List of commands:**\n" do |memo, c|
          memo + "**`#{c.name}`**: #{c.attributes[:description] || '*No description available*'}\n"
        end
      when 5..50
        (available_commands.reduce "**List of commands:**\n" do |memo, c|
          memo + "`#{c.name}`, "
        end)[0..-3]
      else
        event.user.pm(available_commands.reduce("**List of commands:**\n") { |a, e| a + "`#{e.name}`, " })[0..-3]
        'Sending list in PM!'
      end
    end
  end
end

Instance Attribute Details

#attributesObject (readonly)

Returns the value of attribute attributes.



11
12
13
# File 'lib/discordrb/commands/command_bot.rb', line 11

def attributes
  @attributes
end

#prefixObject (readonly)

Returns the value of attribute prefix.



11
12
13
# File 'lib/discordrb/commands/command_bot.rb', line 11

def prefix
  @prefix
end

Instance Method Details

#command(name, attributes = {}, &block) ⇒ Object



84
85
86
87
88
89
90
91
92
# File 'lib/discordrb/commands/command_bot.rb', line 84

def command(name, attributes = {}, &block)
  if name.is_a? Array
    new_command = Command.new(name[0], attributes, &block)
    name.each { |n| @commands[n] = new_command }
    new_command
  else
    @commands[name] = Command.new(name, attributes, &block)
  end
end

#create_message(data) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/discordrb/commands/command_bot.rb', line 116

def create_message(data)
  message = Discordrb::Message.new(data, self)
  event = CommandEvent.new(message, self)

  return unless message.content.start_with? @prefix
  chain = message.content[@prefix.length..-1]

  if chain.strip.empty?
    debug('Chain is empty')
    return
  end

  execute_chain(chain, event)
end

#execute_chain(chain, event) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/discordrb/commands/command_bot.rb', line 131

def execute_chain(chain, event)
  t = Thread.new do
    @event_threads << t
    Thread.current[:discordrb_name] = "ct-#{@current_thread += 1}"
    begin
      debug("Parsing command chain #{chain}")
      result = (@attributes[:advanced_functionality]) ? CommandChain.new(chain, self).execute(event) : simple_execute(chain, event)
      result = event.saved_message + (result || '')
      event.respond result unless result.nil? || result.empty?
    rescue => e
      log_exception(e)
    ensure
      @event_threads.delete(t)
    end
  end
end

#execute_command(name, event, arguments, chained = false) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/discordrb/commands/command_bot.rb', line 94

def execute_command(name, event, arguments, chained = false)
  debug("Executing command #{name} with arguments #{arguments}")
  command = @commands[name]
  unless command
    event.respond @attributes[:command_doesnt_exist_message].gsub('%command%', name.to_s) if @attributes[:command_doesnt_exist_message]
    return
  end
  if permission?(user(event.user.id), command.attributes[:permission_level], event.server)
    event.command = command
    result = command.call(event, arguments, chained)
    result.to_s
  else
    event.respond "You don't have permission to execute command `#{name}`!"
  end
end

#permission?(user, level, server) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
159
160
161
# File 'lib/discordrb/commands/command_bot.rb', line 156

def permission?(user, level, server)
  determined_level = server.nil? ? 0 : user.roles[server.id].each.reduce(0) do |memo, role|
    [@permissions[:roles][role.id] || 0, memo].max
  end
  [@permissions[:users][user.id] || 0, determined_level].max >= level
end

#set_role_permission(id, level) ⇒ Object



152
153
154
# File 'lib/discordrb/commands/command_bot.rb', line 152

def set_role_permission(id, level)
  @permissions[:roles][id] = level
end

#set_user_permission(id, level) ⇒ Object



148
149
150
# File 'lib/discordrb/commands/command_bot.rb', line 148

def set_user_permission(id, level)
  @permissions[:users][id] = level
end

#simple_execute(chain, event) ⇒ Object



110
111
112
113
114
# File 'lib/discordrb/commands/command_bot.rb', line 110

def simple_execute(chain, event)
  return nil if chain.empty?
  args = chain.split(' ')
  execute_command(args[0].to_sym, event, args[1..-1])
end