diff --git a/source/main.rb b/source/main.rb index edd3ce3..3128c73 100644 --- a/source/main.rb +++ b/source/main.rb @@ -10,8 +10,9 @@ module Vrobot4 type = botinfo["type"] serv = Server::get_server_type(type).new(botinfo) - botinfo["modules"].each \ - {|mod| serv.load_mod mod} if botinfo.key? "modules" + if botinfo.key? "modules" then for mod in botinfo["modules"] do + serv.load_mod mod + end end serv end diff --git a/source/module.rb b/source/module.rb index bdd4e4f..4d5fa10 100644 --- a/source/module.rb +++ b/source/module.rb @@ -2,7 +2,7 @@ module Vrobot4::Module # A command function. Holds extra info for i.e. permissions. class Command - attr_reader :help_str # Help string for this command. + attr_reader :help_str # @return [String] help string for this command # @param fn [Method] method to be called on run # @param help [String] help string for this command @@ -27,6 +27,8 @@ module Vrobot4::Module end # Calls the method attached to this command. + # @param m [Vrobot4::Server::Message] message for context + # @param argv [String] argument string def run m, argv @function.call(m, argv) end @@ -51,10 +53,10 @@ module Vrobot4::Module # Callback for command receiving. # @param m [Vrobot4::Server::Message] message that triggered this call # @param cnam [String] name of command to call - # @param argv [Array] array of string arguments + # @param argv [String] array of string arguments # @return [Boolean] if this should block further command callbacks def on_command m, cnam, argv - if (cmd = all_cmds(m)[cnam]) + if (cmd = cmds(m)[cnam]) begin cmd.run(m, argv) rescue @@ -69,7 +71,7 @@ module Vrobot4::Module # Gets all commands usable in a specified context. # @param m [Vrobot4::Server::Message] message for context # @return [Hash] a hash of all commands by name - def all_cmds m + def cmds m @commands.select {|name, cmd| cmd.usable_in? m} end @@ -96,24 +98,37 @@ module Vrobot4::Module # Specifiers include: # [N] A number. # [S] An arbitrary string. + # [*] Any amount of arbitrary arguments. Must be the last optional arg. # - # @param argv [Array] array of arguments + # @param argv [String, Array] array of arguments or a string # @param req [String] specifier string of required arguments # @param opt [String] specifier string of optional arguments + # @return argv def check_args argv, req, opt = "" - if argv.length < req.length - raise ArgumentError, "Not enough arguments" - elsif argv.length > req.length + opt.length - raise ArgumentError, "Too many arguments" - else - (0...req.length).each do |i| + if argv.is_a? Array then + if argv.length < req.length + raise ArgumentError, "Not enough arguments" + elsif opt[-1] != '*' and argv.length > req.length + opt.length + raise ArgumentError, "Too many arguments" + end + + for i in (0 ... req.length) check_arg argv[i], i, req[i] end - (0...argv.length - req.length).each do |i| - check_arg argv[i + req.length], i + req.length, opt[i] + for i in (0 ... argv.length - req.length) + break if opt[i] == '*' + argn = i + req.length + check_arg argv[argn], argn, opt[i] + end + else + if opt.length + check_arg argv, 0, opt[0] if argv.length + else + check_arg argv, 0, req[0] end end + argv end private @@ -123,6 +138,9 @@ module Vrobot4::Module unless Vrobot4.is_num? arg.strip raise ArgumentError, "Expected a number for arg " + i.to_s end + when 'S' # Don't need to check anything here. + else + raise ArgumentError, "Invalid argument specifier " + req.to_s end end end diff --git a/source/modules/mod_audio.rb b/source/modules/mod_audio.rb index a49ac28..9312254 100644 --- a/source/modules/mod_audio.rb +++ b/source/modules/mod_audio.rb @@ -92,7 +92,7 @@ class Mod_Audio < Vrobot4::Module::Module def push_queue m, argv m.reply "Queueing '" + uri.to_s + "'..." - uri = URI.parse argv.join(" ") + uri = URI.parse argv qi = @queue.push QueueItem.new(uri) m.reply "'" + uri.to_s + "' loaded (%i sec, %i bytes)" % @@ -100,7 +100,7 @@ class Mod_Audio < Vrobot4::Module::Module end def start_playback m, qi - m.serv.play m, qi.get_file + m.serv.voice_play m, qi.get_file end end diff --git a/source/modules/mod_discord.rb b/source/modules/mod_discord.rb index bf09698..a647cc5 100644 --- a/source/modules/mod_discord.rb +++ b/source/modules/mod_discord.rb @@ -19,7 +19,7 @@ class Mod_Discord < Vrobot4::Module::Module def c_purge m, argv check_args argv, "N" - n = argv[0].to_i + n = argv.to_i n = 2 if n < 2 n = 100 if n > 100 m.chan.real.prune n diff --git a/source/modules/mod_doomrla.rb b/source/modules/mod_doomrla.rb index 3154123..7c678b2 100644 --- a/source/modules/mod_doomrla.rb +++ b/source/modules/mod_doomrla.rb @@ -1,7 +1,7 @@ require 'open-uri' require 'json' -# +#-- # ===== WARNING ===== # # !!! INCOMING SPAGHETTI !!! @@ -31,8 +31,7 @@ class Mod_DoomRLA < Vrobot4::Module::Module end def c_weaponinfo m, argv - name = argv.join(" ") - w = @winfo.select {|wep| wep if wep["Name"].casecmp? name}[0] + w = @winfo.select {|wep| wep if wep["Name"].casecmp? argv}[0] raise ArgumentError, "Weapon not found" if w == nil t = "%s %s damage\n" % [w["Damage"], w["DamageType"]] t << "%s shots\n" % [w["Shots"]] if w["Shots"].to_i > 1 @@ -53,10 +52,9 @@ class Mod_DoomRLA < Vrobot4::Module::Module end def c_monsterinfo m, argv - name = argv.join(" ") mi = @minfo.select do |mon| - mon if mon["Name"].casecmp? name or - mon["Tags"].split(", ").include? name + mon if mon["Name"].casecmp? argv or + mon["Tags"].split(", ").include? argv end raise ArgumentError, "No monsters found" if mi == nil mi.first(3).each do |w| @@ -78,7 +76,7 @@ class Mod_DoomRLA < Vrobot4::Module::Module embed.title = "[%s] %s" % [w["Difficulty"], w["Name"]] embed.title << " %s" % [w["Weapon"]] if w["Weapon"] embed.image = Discordrb::Webhooks::EmbedImage.new \ - url: w["Sprite"] if w.key? "Sprite" + url: w["Sprite"] if w["Sprite"] embed.description = t end end diff --git a/source/modules/mod_fun.rb b/source/modules/mod_fun.rb index 77baf05..1ab6f1f 100644 --- a/source/modules/mod_fun.rb +++ b/source/modules/mod_fun.rb @@ -29,15 +29,12 @@ class Mod_Fun < Vrobot4::Module::Module def c_nyan (m, argv) m.reply "nyan " * (rand(10) + 1) + "~" end def c_box m, argv - str = argv.join(" ") - text = str + "\n" - raise ArgumentError, "String too long" if str.length > 30 - if str.length > 2 - for i in (1..str.length - 2) - text << str[i] + " " * (str.length - 2) + str.reverse[i] + "\n" - end - end - text << str.reverse + text = argv + "\n" + raise ArgumentError, "String too long" if argv.length > 30 + if argv.length > 2 then for i in (1..argv.length - 2) + text << argv[i] + " " * (argv.length - 2) + argv.reverse[i] + "\n" + end end + text << argv.reverse m.reply_b text end @@ -48,8 +45,8 @@ class Mod_Fun < Vrobot4::Module::Module def c_marble m, argv check_args argv, "", "N" - if argv.length == 0 then n = 20 - else n = argv[0].to_i end + if argv.empty? then n = 20 + else n = argv.to_i end if m.serv.flags.include? "L" and n > 200 then n = 200 elsif n > 1000 then n = 1000 end @@ -64,8 +61,7 @@ class Mod_Fun < Vrobot4::Module::Module end def c_quote m, argv - argv = argv.join(" ") - if argv.length == 0 + if argv.empty? q, num = nil, nil max = JSON.parse(open(QDB + "/interface.cgi").read)["numQuotes"] loop do diff --git a/source/modules/mod_util.rb b/source/modules/mod_util.rb index 1919420..883baef 100644 --- a/source/modules/mod_util.rb +++ b/source/modules/mod_util.rb @@ -14,7 +14,7 @@ class Mod_Util < Vrobot4::Module::Module end def c_rand m, argv - check_args argv, "N", "N" + argv = check_args argv.split, "N", "N" min, max = 0, argv[0].to_f min, max = max, argv[1].to_f if argv.length >= 2 max, min = min, max if max < min @@ -23,7 +23,7 @@ class Mod_Util < Vrobot4::Module::Module end def c_decide m, argv - argv = argv.join(" ").split(",").each {|arg| arg.chomp!} + argv = check_args argv.split(/\s*,\s*/), "S", "*" m.reply argv.sample end diff --git a/source/server.rb b/source/server.rb index 1a490eb..f2afea6 100644 --- a/source/server.rb +++ b/source/server.rb @@ -13,20 +13,18 @@ module Vrobot4::Server # @!visibility private def c_help m, argv - check_args argv, "", "S" - if argv.length == 0 + if argv.empty? cmds = [] - m.serv.each_mod {|mod| cmds << mod.all_cmds(m).keys.join(", ")} + m.serv.each_mod {|mod| cmds << mod.cmds(m).keys.join(", ")} cmds.delete "" m.reply "Commands:", cmds.join(", ") else - name = argv[0] m.serv.each_mod do |mod| - if (cmd = mod.get_cmd m, name) - return m.reply name + ":", cmd.help_str + if (cmd = mod.cmds(m)[argv]) + return m.reply argv + ":", cmd.help_str end end - m.reply "Command not found:", name + m.reply "Command not found:", argv end end @@ -47,7 +45,7 @@ module Vrobot4::Server # @!visibility private def c_modr m, argv - check_args argv, "S", "S" + argv = check_args argv.split, "S", "S" m.serv.drop_mod argv[0] load argv[1], true if argv.length > 1 m.serv.load_mod argv[0] @@ -55,25 +53,23 @@ module Vrobot4::Server # @!visibility private def c_modl m, argv - check_args argv, "S" - m.serv.load_mod argv[0] + m.serv.load_mod argv end # @!visibility private def c_modu m, argv - check_args argv, "S" - m.serv.drop_mod argv[0] + m.serv.drop_mod argv end # @!visibility private def c_dbg m, argv check_args argv, "N" - Vrobot4.debug = argv[0].to_i + Vrobot4.debug = argv.to_i end # @!visibility private def on_command m, cnam, argv - Vrobot4.log :DEBUGV, "command", cnam.to_s, argv.to_s + Vrobot4.log :DEBUGV, "command", cnam.to_s, argv super end end @@ -81,21 +77,21 @@ module Vrobot4::Server # Generic user information. May be extended. class User - attr_reader :name # Plaintext name of the user. - attr_reader :roles # List of user's roles. + attr_reader :name # @return [String] plaintext name of the user + attr_reader :roles # @return [String] list of user's roles end # Generic channel information. May be extended. class Channel - attr_reader :name # Plaintext name of the channel. + attr_reader :name # @return [String] plaintext name of the channel end # Generic event information. May not be extended. class Message - attr_reader :msg # Plaintext of message (if any.) - attr_reader :user # User that triggered this message (if any.) - attr_reader :chan # Channel this message was sent to (if any.) - attr_reader :serv # Server this message was sent to. + attr_reader :msg # @return [String] plaintext of message + attr_reader :user # @return [User] user that triggered this message + attr_reader :chan # @return [Channel] channel this message was sent to + attr_reader :serv # @return [Server] server this message was sent to # @param info [Hash] A hash containing message info. Keys may be omitted. # [:msg] Plaintext of message. @@ -126,7 +122,7 @@ module Vrobot4::Server # Generic server interface. class Server - attr_reader :mprm # Module permissions for this server. + attr_reader :mprm # @return [Hash] module permissions for this server # @param info [Hash] arbitrary extra information for this server def initialize info @@ -195,21 +191,26 @@ module Vrobot4::Server # Basis for an audio-enabled server interface. class AudioServer < Server # Joins a voice channel, using a message for context. + # @param m [Vrobot4::Server::Message] message for context def voice_join m raise NotImplementedError, "AudioServer#voice_join not implemented" end # Quits a voice channel, using a message for context. + # @param m [Vrobot4::Server::Message] message for context def voice_quit m raise NotImplementedError, "AudioServer#voice_quit not implemented" end # Plays an arbitrary audio file in a given context. - def play m, io - raise NotImplementedError, "AudioServer#play not implemented" + # @param m [Vrobot4::Server::Message] message for context + # @param io [IO] audio stream to play + def voice_play m, io + raise NotImplementedError, "AudioServer#voice_play not implemented" end # Check if the bot is playing audio in a given context. + # @param m [Vrobot4::Server::Message] message for context def is_playing? m raise NotImplementedError, "AudioServer#is_playing? not implemented" end diff --git a/source/servers/sv_discord.rb b/source/servers/sv_discord.rb index 6fd9709..f8691f5 100644 --- a/source/servers/sv_discord.rb +++ b/source/servers/sv_discord.rb @@ -32,9 +32,8 @@ class Sv_Discord < Vrobot4::Server::AudioServer reply_b: -> (text) {evt.respond "```\n" + text + "```"} if m.msg.start_with? '.' - argv = m.msg.split - cnam = argv.shift[1..-1] - on_command m, cnam, argv + arg = m.msg.split(' ', 2) + on_command m, arg[0][1..-1], (arg[1] or "") else on_message m end @@ -53,8 +52,8 @@ class Sv_Discord < Vrobot4::Server::AudioServer @bot.voice_destroy m.chan.real.server.id end - # (see Vrobot4::Server::AudioServer#play) - def play m, io + # (see Vrobot4::Server::AudioServer#voice_play) + def voice_play m, io v = @bot.voice(m.chan.real) raise ArgumentError, "Invalid i/o stream" unless io raise RuntimeError, "I'm not in a voice channel" unless v