+ # Returns +true+ if _name_ is a known botmodule of class kl
+ def knows?(name, kl)
+ return @commandmappers[kl.to_sym].has_key?(name.to_sym)
+ end
+
+ # Registers botmodule _botmodule_ with command _cmd_ and command path _auth_path_
+ def register(botmodule, cmd, auth_path)
+ raise TypeError, "First argument #{botmodule.inspect} is not of class BotModule" unless botmodule.kind_of?(BotModule)
+ kl = botmodule.botmodule_class
+ @commandmappers[kl.to_sym][cmd.to_sym] = {:botmodule => botmodule, :auth => auth_path}
+ h = @commandmappers[kl.to_sym][cmd.to_sym]
+ # debug "Registered command mapper for #{cmd.to_sym} (#{kl.to_sym}): #{h[:botmodule].name} with command path #{h[:auth]}"
+ end
+
+ def add_botmodule(botmodule)
+ raise TypeError, "Argument #{botmodule.inspect} is not of class BotModule" unless botmodule.kind_of?(BotModule)
+ kl = botmodule.botmodule_class
+ raise "#{kl.to_s} #{botmodule.name} already registered!" if @botmodules[kl.to_sym].include?(botmodule)
+ @botmodules[kl.to_sym] << botmodule
+ end
+
+ # Returns an array of the loaded plugins
+ def core_modules
+ @botmodules[:coremodule]
+ end
+
+ # Returns an array of the loaded plugins
+ def plugins
+ @botmodules[:plugin]
+ end
+
+ # Returns a hash of the registered message prefixes and associated
+ # plugins
+ def plugin_commands
+ @commandmappers[:plugin]
+ end
+
+ # Returns a hash of the registered message prefixes and associated
+ # core modules
+ def core_commands
+ @commandmappers[:coremodule]
+ end
+
+ # Makes a string of error _err_ by adding text _str_
+ def report_error(str, err)
+ ([str, err.inspect] + err.backtrace).join("\n")
+ end
+
+ # This method is the one that actually loads a module from the
+ # file _fname_
+ #
+ # _desc_ is a simple description of what we are loading (plugin/botmodule/whatever)
+ #
+ # It returns the Symbol :loaded on success, and an Exception
+ # on failure
+ #
+ def load_botmodule_file(fname, desc=nil)
+ # create a new, anonymous module to "house" the plugin
+ # the idea here is to prevent namespace pollution. perhaps there
+ # is another way?
+ plugin_module = Module.new
+
+ desc = desc.to_s + " " if desc
+
+ begin
+ plugin_string = IO.readlines(fname).join("")
+ debug "loading #{desc}#{fname}"
+ plugin_module.module_eval(plugin_string, fname)
+ return :loaded
+ rescue Exception => err
+ # rescue TimeoutError, StandardError, NameError, LoadError, SyntaxError => err
+ warning report_error("#{desc}#{fname} load failed", err)
+ bt = err.backtrace.select { |line|
+ line.match(/^(\(eval\)|#{fname}):\d+/)
+ }
+ bt.map! { |el|
+ el.gsub(/^\(eval\)(:\d+)(:in `.*')?(:.*)?/) { |m|
+ "#{fname}#{$1}#{$3}"
+ }
+ }
+ msg = err.to_str.gsub(/^\(eval\)(:\d+)(:in `.*')?(:.*)?/) { |m|
+ "#{fname}#{$1}#{$3}"
+ }
+ newerr = err.class.new(msg)
+ newerr.set_backtrace(bt)
+ return newerr
+ end
+ end
+ private :load_botmodule_file
+
+ # add one or more directories to the list of directories to
+ # load botmodules from
+ #
+ # TODO find a way to specify necessary plugins which _must_ be loaded
+ #
+ def add_botmodule_dir(*dirlist)
+ @dirs += dirlist
+ debug "Botmodule loading path: #{@dirs.join(', ')}"