diff options
author | Giuseppe Bilotta <giuseppe.bilotta@gmail.com> | 2009-08-08 01:40:18 +0200 |
---|---|---|
committer | Giuseppe Bilotta <giuseppe.bilotta@gmail.com> | 2009-08-12 00:56:27 +0200 |
commit | a993d1c358e24ab85621568c10411c5496e2dea8 (patch) | |
tree | acde205a3ed605476f6eabf6e04c0b0441a7e10f | |
parent | 74d7d02ed07740e50c3f87da9ecedf13397729ea (diff) |
Better handling of MessageMapper failures
The plugin fallback method is now passed the list of failures.
Failures themselves are encapsulated in their own data type, making it
easier to handle failures that should inform the user with something
more detailed than the classic 'usage' pattern.
It's still up to the fallback method to make use (e.g. echo) the
relevant messages.
-rw-r--r-- | lib/rbot/messagemapper.rb | 78 | ||||
-rw-r--r-- | lib/rbot/plugins.rb | 9 |
2 files changed, 73 insertions, 14 deletions
diff --git a/lib/rbot/messagemapper.rb b/lib/rbot/messagemapper.rb index c1691aff..ca076e4a 100644 --- a/lib/rbot/messagemapper.rb +++ b/lib/rbot/messagemapper.rb @@ -52,6 +52,57 @@ class Bot # {:option => "bar", :otheroption => "baz"} # See the #map method for more details. class MessageMapper + + class Failure + STRING = "template %{template} failed to recognize message %{message}" + FRIENDLY = "I failed to understand the command" + attr_reader :template + attr_reader :message + def initialize(tmpl, msg) + @template = tmpl + @message = msg + end + + def to_s + STRING % { + :template => template.template, + :regexp => template.regexp, + :message => message.message, + :action => template.options[:action] + } + end + end + + # failures with a friendly message + class FriendlyFailure < Failure + def friendly + self.class::FRIENDLY rescue FRIENDLY + end + end + + class NotPrivateFailure < FriendlyFailure + STRING = "template %{template} is not configured for private messages" + FRIENDLY = "the command must not be given in private" + end + + class NotPublicFailure < FriendlyFailure + STRING = "template %{template} is not configured for public messages" + FRIENDLY = "the command must not be given in public" + end + + class NoMatchFailure < Failure + STRING = "%{message} does not match %{template} (%{regex})" + end + + class PartialMatchFailure < Failure + STRING = "%{message} only matches %{template} (%{regex}) partially" + end + + class NoActionFailure < FriendlyFailure + STRING = "%{template} calls undefined action %{action}" + FRIENDLY = "uh-ho, somebody forgot to tell me how to do that ..." + end + # used to set the method name used as a fallback for unmatched messages. # The default fallback is a method called "usage". attr_writer :fallback @@ -194,13 +245,13 @@ class Bot return false if @templates.empty? failures = [] @templates.each do |tmpl| - options, failure = tmpl.recognize(m) - if options.nil? - failures << [tmpl, failure] + options = tmpl.recognize(m) + if options.kind_of? Failure + failures << options else action = tmpl.options[:action] unless @parent.respond_to?(action) - failures << [tmpl, "class does not respond to action #{action}"] + failures << NoActionFailure.new(tmpl, m) next end auth = tmpl.options[:full_auth_path] @@ -228,13 +279,13 @@ class Bot return false end end - failures.each {|f, r| - debug "#{f.inspect} => #{r}" + failures.each {|r| + debug "#{r.template.inspect} => #{r}" } debug "no handler found, trying fallback" if @fallback && @parent.respond_to?(@fallback) if m.bot.auth.allow?(@fallback, m.source, m.replyto) - @parent.send(@fallback, m, {}) + @parent.send(@fallback, m, {:failures => failures}) return true end end @@ -531,13 +582,12 @@ class Bot debug "Testing #{m.message.inspect} against #{self.inspect}" - # Early out - return nil, "template #{@template} is not configured for private messages" if @options.has_key?(:private) && !@options[:private] && m.private? - return nil, "template #{@template} is not configured for public messages" if @options.has_key?(:public) && !@options[:public] && !m.private? - matching = @regexp.match(m.message) - return nil, "#{m.message.inspect} doesn't match #{@template} (#{@regexp})" unless matching - return nil, "#{m.message.inspect} only matches #{@template} (#{@regexp}) partially: #{matching[0].inspect}" unless matching[0] == m.message + return MessageMapper::NoMatchFailure.new(self, m) unless matching + return MessageMapper::PartialMatchFailure.new(self, m) unless matching[0] == m.message + + return MessageMapper::NotPrivateFailure.new(self, m) if @options.has_key?(:private) && !@options[:private] && m.private? + return MessageMapper::NotPublicFailure.new(self, m) if @options.has_key?(:public) && !@options[:public] && !m.private? debug_match = matching[1..-1].collect{ |d| d.inspect}.join(', ') debug "#{m.message.inspect} matched #{@regexp} with #{debug_match}" @@ -589,7 +639,7 @@ class Bot } options.delete_if {|k, v| v.nil?} # Remove nil values. - return options, nil + return options end def inspect diff --git a/lib/rbot/plugins.rb b/lib/rbot/plugins.rb index e7905c50..2b4694ad 100644 --- a/lib/rbot/plugins.rb +++ b/lib/rbot/plugins.rb @@ -341,6 +341,15 @@ module Plugins # MessageMapper uses 'usage' as its default fallback method. # def usage(m, params = {}) + if params[:failures].respond_to? :find + friendly = params[:failures].find do |f| + f.kind_of? MessageMapper::FriendlyFailure + end + if friendly + m.reply friendly.friendly + return + end + end m.reply(_("incorrect usage, ask for help using '%{command}'") % {:command => "#{@bot.nick}: help #{m.plugin}"}) end |