vrobot4/source/module.rb

188 lines
6.3 KiB
Ruby
Raw Normal View History

2017-08-11 19:40:43 -07:00
# Module for vrobot4 bot modules.
module Vrobot4::Module
2019-02-23 20:46:40 -08:00
# A command function. Holds extra info such as help and permissions.
class Command
attr_reader :help_str # @return [String] help string for this command
2017-08-11 19:40:43 -07:00
# @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
2017-08-11 19:40:43 -07:00
# Checks if this command is usable in a given context.
# @param m [Vrobot4::Server::Message] message for context
2019-02-23 20:46:40 -08:00
# @return [Boolean] true if command is usable, false otherwise
2017-08-11 15:16:16 -07:00
def usable_in? m
m.user.roles.scan(@roles).any? and @function.owner.usable_in? m
end
2017-08-11 19:40:43 -07:00
# Calls the method attached to this command.
# @param m [Vrobot4::Server::Message] message for context
# @param argv [String] argument string
2019-02-23 20:46:40 -08:00
# @return [void]
def run m, argv
@function.call(m, argv)
end
end
2017-08-11 19:40:43 -07:00
# 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
2019-02-23 20:46:40 -08:00
# @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
2017-08-11 19:40:43 -07:00
# @param info [Hash] arbitrary extra information for this module
2017-08-09 00:52:34 -07:00
def initialize info
@commands = {}
2017-08-09 00:52:34 -07:00
@info = info
2019-02-23 20:46:40 -08:00
Vrobot4.log :DEBUG, "initialized #{self.to_s}"
end
2017-08-11 19:40:43 -07:00
# Callback for message receiving.
# @param m [Vrobot4::Server::Message] message received
# @return [Boolean] if this should block further message callbacks
2017-08-11 15:16:16 -07:00
def on_message m
false
end
2017-08-11 19:40:43 -07:00
# 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
2017-08-11 19:40:43 -07:00
# @return [Boolean] if this should block further command callbacks
2017-08-11 15:16:16 -07:00
def on_command m, cnam, argv
if (cmd = cmds(m)[cnam])
begin
cmd.run(m, argv)
rescue
m.reply "Error:", $!.to_s
end
2017-08-11 15:16:16 -07:00
true
else
2017-08-11 15:16:16 -07:00
false
end
end
2017-08-11 19:40:43 -07:00
# Gets all commands usable in a specified context.
# @param m [Vrobot4::Server::Message] message for context
2019-02-23 20:46:40 -08:00
# @return [Hash<String, Vrobot4::Module::Command>]
# a hash of all commands by name
def cmds m
2019-02-23 20:46:40 -08:00
@commands.select do |name, cmd|
cmd.usable_in? m
end
end
protected
2019-02-23 20:46:40 -08:00
2017-08-11 19:40:43 -07:00
# 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
2019-02-23 16:18:39 -08:00
def register fn, names, help = nil, roles: ?v
2017-08-11 19:40:43 -07:00
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.
2017-08-11 19:40:43 -07:00
#
# @param argv [String, Array] array of arguments or a string
2017-08-11 19:40:43 -07:00
# @param req [String] specifier string of required arguments
# @param opt [String] specifier string of optional arguments
2019-02-23 20:46:40 -08:00
# @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
2019-02-23 22:43:50 -08:00
check_arg argv, 0, req[0]
end
argv
end
private
2019-02-23 20:46:40 -08:00
# 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
2019-02-23 16:18:39 -08:00
when ?N
2017-08-11 19:40:43 -07:00
unless Vrobot4.is_num? arg.strip
2019-02-23 20:46:40 -08:00
raise ArgumentError, "Expected a number for arg #{i}"
end
2019-02-23 16:18:39 -08:00
when ?S # Don't need to check anything here.
else
2019-02-23 20:46:40 -08:00
raise ArgumentError, "Invalid argument specifier #{req}"
end
end
end
2017-08-11 19:40:43 -07:00
# 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)
2019-02-23 20:46:40 -08:00
# @return [void]
2017-08-09 02:57:31 -07:00
def self.add_module_type type, server: nil, servflags: nil
@@module_types[type.type] = {
2017-08-08 21:00:28 -07:00
type: type,
server: server,
servflags: servflags ? /[#{servflags}]/ : nil
2017-08-08 04:32:45 -07:00
}
2019-02-23 20:46:40 -08:00
Vrobot4.log :INFO, "added module type #{type.type}"
end
2017-08-11 19:40:43 -07:00
# 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
2017-08-11 19:40:43 -07:00
2019-02-23 20:46:40 -08:00
# The set of all module types.
2017-08-11 19:40:43 -07:00
@@module_types = {}
end
## EOF