diff options
Diffstat (limited to 'lib/rbot')
-rw-r--r-- | lib/rbot/dbhash.rb | 21 | ||||
-rw-r--r-- | lib/rbot/ircbot.rb | 10 | ||||
-rw-r--r-- | lib/rbot/messagemapper.rb | 121 | ||||
-rw-r--r-- | lib/rbot/plugins.rb | 4 | ||||
-rw-r--r-- | lib/rbot/registry.rb | 21 |
5 files changed, 119 insertions, 58 deletions
diff --git a/lib/rbot/dbhash.rb b/lib/rbot/dbhash.rb index 5ae2ba87..611ec087 100644 --- a/lib/rbot/dbhash.rb +++ b/lib/rbot/dbhash.rb @@ -1,24 +1,3 @@ -# Copyright (C) 2002 Tom Gilbert. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies of the Software and its documentation and acknowledgment shall be -# given in the documentation and software packages that this Software was -# used. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - begin require 'bdb' rescue Exception => e diff --git a/lib/rbot/ircbot.rb b/lib/rbot/ircbot.rb index 11b03f50..f99dd940 100644 --- a/lib/rbot/ircbot.rb +++ b/lib/rbot/ircbot.rb @@ -2,6 +2,13 @@ require 'thread' require 'etc' require 'fileutils' +$debug = false unless $debug +# print +message+ if debugging is enabled +def debug(message=nil) + print "DEBUG: #{message}\n" if($debug && message) + #yield +end + # these first require 'rbot/rbotconfig' require 'rbot/config' @@ -369,6 +376,7 @@ class IrcBot end while(message.length > 0) end + # queue an arbitraty message for the server def sendq(message="") # temporary @socket.queue(message) @@ -429,6 +437,7 @@ class IrcBot sendq "TOPIC #{where} :#{topic}" end + # disconnect from the server and cleanup all plugins and modules def shutdown(message = nil) trap("SIGTERM", "DEFAULT") trap("SIGHUP", "DEFAULT") @@ -539,6 +548,7 @@ class IrcBot return helpstr end + # returns a string describing the current status of the bot (uptime etc) def status secs_up = Time.new - @startup_time uptime = Utils.secs_to_string secs_up diff --git a/lib/rbot/messagemapper.rb b/lib/rbot/messagemapper.rb index c8e2b6ba..b079acd6 100644 --- a/lib/rbot/messagemapper.rb +++ b/lib/rbot/messagemapper.rb @@ -1,38 +1,131 @@ module Irc + + # +MessageMapper+ is a class designed to reduce the amount of regexps and + # string parsing plugins and bot modules need to do, in order to process + # and respond to messages. + # + # You add templates to the MessageMapper which are examined by the handle + # method when handling a message. The templates tell the mapper which + # method in its parent class (your class) to invoke for that message. The + # string is split, optionally defaulted and validated before being passed + # to the matched method. + # + # A template such as "foo :option :otheroption" will match the string "foo + # bar baz" and, by default, result in method +foo+ being called, if + # present, in the parent class. It will receive two parameters, the + # Message (derived from BasicUserMessage) and a Hash containing + # {:option => "bar", :otheroption => "baz"} + # See the #map method for more details. class MessageMapper + # used to set the method name used as a fallback for unmatched messages. + # The default fallback is a method called "usage". attr_writer :fallback + # parent:: parent class which will receive mapped messages + # + # create a new MessageMapper with parent class +parent+. This class will + # receive messages from the mapper via the handle() method. def initialize(parent) @parent = parent - @routes = Array.new + @templates = Array.new @fallback = 'usage' end + # args:: hash format containing arguments for this template + # + # map a template string to an action. example: + # map 'myplugin :parameter1 :parameter2' + # (other examples follow). By default, maps a matched string to an + # action with the name of the first word in the template. The action is + # a method which takes a message and a parameter hash for arguments. + # + # The :action => 'method_name' option can be used to override this + # default behaviour. Example: + # map 'myplugin :parameter1 :parameter2', :action => 'mymethod' + # + # By default whether a handler is fired depends on an auth check. The + # first component of the string is used for the auth check, unless + # overridden via the :auth => 'auth_name' option. + # + # Static parameters (not prefixed with ':' or '*') must match the + # respective component of the message exactly. Example: + # map 'myplugin :foo is :bar' + # will only match messages of the form "myplugin something is + # somethingelse" + # + # Dynamic parameters can be specified by a colon ':' to match a single + # component (whitespace seperated), or a * to such up all following + # parameters into an array. Example: + # map 'myplugin :parameter1 *rest' + # + # You can provide defaults for dynamic components using the :defaults + # parameter. If a component has a default, then it is optional. e.g: + # map 'myplugin :foo :bar', :defaults => {:bar => 'qux'} + # would match 'myplugin param param2' and also 'myplugin param'. In the + # latter case, :bar would be provided from the default. + # + # Components can be validated before being allowed to match, for + # example if you need a component to be a number: + # map 'myplugin :param', :requirements => {:param => /^\d+$/} + # will only match strings of the form 'myplugin 1234' or some other + # number. + # + # Templates can be set not to match public or private messages using the + # :public or :private boolean options. + # + # Further examples: + # + # # match 'karmastats' and call my stats() method + # map 'karmastats', :action => 'stats' + # # match 'karma' with an optional 'key' and call my karma() method + # map 'karma :key', :defaults => {:key => false} + # # match 'karma for something' and call my karma() method + # map 'karma for :key' + # + # # two matches, one for public messages in a channel, one for + # # private messages which therefore require a channel argument + # map 'urls search :channel :limit :string', :action => 'search', + # :defaults => {:limit => 4}, + # :requirements => {:limit => /^\d+$/}, + # :public => false + # plugin.map 'urls search :limit :string', :action => 'search', + # :defaults => {:limit => 4}, + # :requirements => {:limit => /^\d+$/}, + # :private => false + # def map(*args) - @routes << Template.new(*args) + @templates << Template.new(*args) end def each - @routes.each {|route| yield route} + @templates.each {|tmpl| yield tmpl} end def last - @routes.last + @templates.last end + # m:: derived from BasicUserMessage + # + # examine the message +m+, comparing it with each map()'d template to + # find and process a match. Templates are examined in the order they + # were map()'d - first match wins. + # + # returns +true+ if a match is found including fallbacks, +false+ + # otherwise. def handle(m) - return false if @routes.empty? + return false if @templates.empty? failures = [] - @routes.each do |route| - options, failure = route.recognize(m) + @templates.each do |tmpl| + options, failure = tmpl.recognize(m) if options.nil? - failures << [route, failure] + failures << [tmpl, failure] else - action = route.options[:action] ? route.options[:action] : route.items[0] + action = tmpl.options[:action] ? tmpl.options[:action] : tmpl.items[0] next unless @parent.respond_to?(action) - auth = route.options[:auth] ? route.options[:auth] : route.items[0] + auth = tmpl.options[:auth] ? tmpl.options[:auth] : tmpl.items[0] debug "checking auth for #{auth}" if m.bot.auth.allow?(auth, m.source, m.replyto) - debug "route found and auth'd: #{action.inspect} #{options.inspect}" + debug "template match found and auth'd: #{action.inspect} #{options.inspect}" @parent.send(action, m, options) return true end @@ -124,8 +217,8 @@ module Irc return nil, "Unused components were left: #{components.join '/'}" unless components.empty? - return nil, "route is not configured for private messages" if @options.has_key?(:private) && !@options[:private] && m.private? - return nil, "route is not configured for public messages" if @options.has_key?(:public) && !@options[:public] && !m.private? + return nil, "template is not configured for private messages" if @options.has_key?(:private) && !@options[:private] && m.private? + return nil, "template is not configured for public messages" if @options.has_key?(:public) && !@options[:public] && !m.private? options.delete_if {|k, v| v.nil?} # Remove nil values. return options, nil @@ -137,7 +230,7 @@ module Irc "<#{self.class.to_s} #{@items.collect{|c| c.kind_of?(String) ? c : c.inspect}.join(' ').inspect}#{default_str}#{when_str}>" end - # Verify that the given value passes this route's requirements + # Verify that the given value passes this template's requirements def passes_requirements?(name, value) return @defaults.key?(name) && @defaults[name].nil? if value.nil? # Make sure it's there if it should be diff --git a/lib/rbot/plugins.rb b/lib/rbot/plugins.rb index d98630e1..4e618f61 100644 --- a/lib/rbot/plugins.rb +++ b/lib/rbot/plugins.rb @@ -8,8 +8,8 @@ module Plugins # # map(template, options):: # map is the new, cleaner way to respond to specific message formats - # without littering your plugin code with regexps - # examples: + # without littering your plugin code with regexps. examples: + # # plugin.map 'karmastats', :action => 'karma_stats' # # # while in the plugin... diff --git a/lib/rbot/registry.rb b/lib/rbot/registry.rb index cd78dcbf..5228d223 100644 --- a/lib/rbot/registry.rb +++ b/lib/rbot/registry.rb @@ -1,24 +1,3 @@ -# Copyright (C) 2002 Tom Gilbert. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies of the Software and its documentation and acknowledgment shall be -# given in the documentation and software packages that this Software was -# used. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - require 'rbot/dbhash' module Irc |