188 lines
6.3 KiB
Ruby
188 lines
6.3 KiB
Ruby
# Module for vrobot4 bot modules.
|
|
module Vrobot4::Module
|
|
# A command function. Holds extra info such as help and permissions.
|
|
class 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
|
|
# @param roles [String] list of roles that can use this command
|
|
def initialize fn, help, roles
|
|
@function = fn
|
|
@help_str = help
|
|
@roles = /[#{roles}]/
|
|
end
|
|
|
|
# Checks if this command is usable in a given context.
|
|
# @param m [Vrobot4::Server::Message] message for context
|
|
# @return [Boolean] true if command is usable, false otherwise
|
|
def usable_in? m
|
|
m.user.roles.scan(@roles).any? and @function.owner.usable_in? m
|
|
end
|
|
|
|
# Calls the method attached to this command.
|
|
# @param m [Vrobot4::Server::Message] message for context
|
|
# @param argv [String] argument string
|
|
# @return [void]
|
|
def run m, argv
|
|
@function.call(m, argv)
|
|
end
|
|
end
|
|
|
|
# A bot module. Holds commands and callbacks.
|
|
class Module
|
|
# Checks if this module is usable in a given context.
|
|
# @param m [Vrobot4::Server::Message] message for context
|
|
# @return [Boolean] true if usable, false otherwise
|
|
def self.usable_in? m
|
|
role = m.user.roles
|
|
mprm = m.serv.mprm
|
|
retm, retc, retr = true, false, false
|
|
retm = mprm[:glob][self] if mprm[:glob].key? self
|
|
retc = mprm[:chan][self][m.chan] if mprm[:chan].key? self
|
|
retr = mprm[:role][self].scan /[#{role}]/ if mprm[:role].key? self
|
|
retm or retc or retr
|
|
end
|
|
|
|
# @param info [Hash] arbitrary extra information for this module
|
|
def initialize info
|
|
@commands = {}
|
|
@info = info
|
|
Vrobot4.log :DEBUG, "initialized #{self.to_s}"
|
|
end
|
|
|
|
# Callback for message receiving.
|
|
# @param m [Vrobot4::Server::Message] message received
|
|
# @return [Boolean] if this should block further message callbacks
|
|
def on_message m
|
|
false
|
|
end
|
|
|
|
# Callback for command receiving.
|
|
# @param m [Vrobot4::Server::Message] message that triggered this call
|
|
# @param cnam [String] name of command to call
|
|
# @param argv [String] array of string arguments
|
|
# @return [Boolean] if this should block further command callbacks
|
|
def on_command m, cnam, argv
|
|
if (cmd = cmds(m)[cnam])
|
|
begin
|
|
cmd.run(m, argv)
|
|
rescue
|
|
m.reply "Error:", $!.to_s
|
|
end
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
# Gets all commands usable in a specified context.
|
|
# @param m [Vrobot4::Server::Message] message for context
|
|
# @return [Hash<String, Vrobot4::Module::Command>]
|
|
# a hash of all commands by name
|
|
def cmds m
|
|
@commands.select do |name, cmd|
|
|
cmd.usable_in? m
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
# Registers a command into this module.
|
|
# @param fn [Symbol] name of method to add
|
|
# @param names [String, Array] name(s) to add this command by
|
|
# @param help [String] help string to use for this command
|
|
# @param roles [String] roles to allow this command to use
|
|
# @return [Vrobot4::Module::Command] command added
|
|
def register fn, names, help = nil, roles: ?v
|
|
help = "No help available for this command." if help == nil
|
|
cmd = Command.new(self.method(fn), help, roles).freeze
|
|
if names.is_a? String
|
|
@commands[names] = cmd
|
|
else
|
|
names.each {|name| @commands[name] = cmd}
|
|
end
|
|
cmd
|
|
end
|
|
|
|
# Check argument validity and count.
|
|
#
|
|
# Specifiers include:
|
|
# [N] A number.
|
|
# [S] An arbitrary string.
|
|
# [*] Any amount of arbitrary arguments. Must be the last optional arg.
|
|
#
|
|
# @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 [String, Array] argv
|
|
def check_args argv, req, opt = ""
|
|
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
|
|
|
|
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
|
|
check_arg argv, 0, req[0]
|
|
end
|
|
argv
|
|
end
|
|
|
|
private
|
|
|
|
# Helper function for {#check_args}.
|
|
# @param arg [String] the argument to check
|
|
# @param i [Integer] which argument this is
|
|
# @param req [String] type that the argument should be
|
|
# @return [void]
|
|
def check_arg arg, i, req
|
|
case req
|
|
when ?N
|
|
unless Vrobot4.is_num? arg.strip
|
|
raise ArgumentError, "Expected a number for arg #{i}"
|
|
end
|
|
when ?S # Don't need to check anything here.
|
|
else
|
|
raise ArgumentError, "Invalid argument specifier #{req}"
|
|
end
|
|
end
|
|
end
|
|
|
|
# Adds a module type to the global list.
|
|
# @param type [Class] module type to add
|
|
# @param server [String] server type this module is restricted to (or none)
|
|
# @param servflags [String] flags the server must have to use this (or none)
|
|
# @return [void]
|
|
def self.add_module_type type, server: nil, servflags: nil
|
|
@@module_types[type.type] = {
|
|
type: type,
|
|
server: server,
|
|
servflags: servflags ? /[#{servflags}]/ : nil
|
|
}
|
|
Vrobot4.log :INFO, "added module type #{type.type}"
|
|
end
|
|
|
|
# Gets a module type by name from the global list.
|
|
# @param name [String] name of the module type to find
|
|
# @return [Hash] a hash containing info about the type
|
|
def self.get_module_type name
|
|
@@module_types[name]
|
|
end
|
|
|
|
# The set of all module types.
|
|
@@module_types = {}
|
|
end
|
|
|
|
## EOF
|