+ # 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
+ # each plugin uses its own textdomain, we bind it automatically here
+ bindtextdomain_to(plugin_module, "rbot-#{File.basename(fname, '.rb')}")
+
+ desc = desc.to_s + " " if desc
+
+ begin
+ plugin_string = IO.read(fname)
+ debug "loading #{desc}#{fname}"
+ plugin_module.module_eval(plugin_string, fname)
+ return :loaded
+ rescue Exception => err
+ # rescue TimeoutError, StandardError, NameError, LoadError, SyntaxError => err
+ error 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(', ')}"
+ end
+
+ def clear_botmodule_dirs
+ @dirs.clear
+ debug "Botmodule loading path cleared"