class Discordrb::Commands::CommandChain
Command
chain, may have multiple commands, nested and commands
Public Class Methods
new(chain, bot, subchain = false)
click to toggle source
@param chain [String] The string the chain should be parsed from. @param bot [CommandBot] The bot that executes this command chain. @param subchain [true, false] Whether this chain is a sub chain of another chain.
# File lib/discordrb/commands/parser.rb, line 143 def initialize(chain, bot, subchain = false) @attributes = bot.attributes @chain = chain @bot = bot @subchain = subchain end
Public Instance Methods
execute(event)
click to toggle source
Divides the command chain into chain arguments and command chain, then executes them both. @param event [CommandEvent] The event to execute the command with. @return [String] the result of the command chain execution.
# File lib/discordrb/commands/parser.rb, line 278 def execute(event) old_chain = @chain @bot.debug 'Executing bare chain' result = execute_bare(event) @chain_args ||= [] @bot.debug "Found chain args #{@chain_args}, preliminary result #{result}" @chain_args.each do |arg| case arg.first when 'repeat' new_result = '' executed_chain = divide_chain(old_chain).last arg[1].to_i.times do chain_result = CommandChain.new(executed_chain, @bot).execute(event) new_result += chain_result if chain_result end result = new_result # TODO: more chain arguments end end result end
execute_bare(event)
click to toggle source
Parses the command chain itself, including sub-chains, and executes it. Executes only the command chain, without its chain arguments. @param event [CommandEvent] The event to execute the chain with. @return [String] the result of the execution.
# File lib/discordrb/commands/parser.rb, line 154 def execute_bare(event) b_start = -1 b_level = 0 result = '' quoted = false escaped = false hacky_delim, hacky_space, hacky_prev, hacky_newline = [0xe001, 0xe002, 0xe003, 0xe004].pack('U*').chars @chain.each_char.each_with_index do |char, index| # Escape character if char == '\\' && !escaped escaped = true next elsif escaped && b_level <= 0 result += char escaped = false next end if quoted # Quote end if char == @attributes[:quote_end] quoted = false next end if b_level <= 0 case char when @attributes[:chain_delimiter] result += hacky_delim next when @attributes[:previous] result += hacky_prev next when ' ' result += hacky_space next when "\n" result += hacky_newline next end end else case char when @attributes[:quote_start] # Quote begin quoted = true next when @attributes[:sub_chain_start] b_start = index if b_level.zero? b_level += 1 end end result += char if b_level <= 0 next unless char == @attributes[:sub_chain_end] && !quoted b_level -= 1 next unless b_level.zero? nested = @chain[b_start + 1..index - 1] subchain = CommandChain.new(nested, @bot, true) result += subchain.execute(event) end event.respond("Your subchains are mismatched! Make sure you don't have any extra #{@attributes[:sub_chain_start]}'s or #{@attributes[:sub_chain_end]}'s") unless b_level.zero? @chain = result @chain_args, @chain = divide_chain(@chain) prev = '' chain_to_split = @chain # Don't break if a command is called the same thing as the chain delimiter chain_to_split = chain_to_split.slice(1..-1) if !@attributes[:chain_delimiter].empty? && chain_to_split.start_with?(@attributes[:chain_delimiter]) first = true split_chain = if @attributes[:chain_delimiter].empty? [chain_to_split] else chain_to_split.split(@attributes[:chain_delimiter]) end split_chain.each do |command| command = @attributes[:chain_delimiter] + command if first && @chain.start_with?(@attributes[:chain_delimiter]) first = false command = command.strip # Replace the hacky delimiter that was used inside quotes with actual delimiters command = command.gsub hacky_delim, @attributes[:chain_delimiter] first_space = command.index ' ' command_name = first_space ? command[0..first_space - 1] : command arguments = first_space ? command[first_space + 1..] : '' # Append a previous sign if none is present arguments += @attributes[:previous] unless arguments.include? @attributes[:previous] arguments = arguments.gsub @attributes[:previous], prev # Replace hacky previous signs with actual ones arguments = arguments.gsub hacky_prev, @attributes[:previous] arguments = arguments.split ' ' # Replace the hacky spaces/newlines with actual ones arguments.map! do |elem| elem.gsub(hacky_space, ' ').gsub(hacky_newline, "\n") end # Finally execute the command prev = @bot.execute_command(command_name.to_sym, event, arguments, split_chain.length > 1 || @subchain) # Stop chain if execute_command failed (maybe the command doesn't exist, or permissions failed, etc.) break unless prev end prev end
Private Instance Methods
divide_chain(chain)
click to toggle source
# File lib/discordrb/commands/parser.rb, line 308 def divide_chain(chain) chain_args_index = chain.index(@attributes[:chain_args_delim]) unless @attributes[:chain_args_delim].empty? chain_args = [] if chain_args_index chain_args = chain[0..chain_args_index].split ',' # Split up the arguments chain_args.map! do |arg| arg.split ' ' end chain = chain[chain_args_index + 1..] end [chain_args, chain] end