+ # MessageParameter is a class that collects all the necessary information
+ # about a message (dynamic) parameter (the :param or *param that can be found
+ # in a #map).
+ #
+ # It has a +name+ attribute, +multi+ and +optional+ booleans that tell if the
+ # parameter collects more than one word, and if it's optional (respectively).
+ # In the latter case, it can also have a default value.
+ #
+ # It is possible to assign a collector to a MessageParameter. This can be either
+ # a Regexp with captures or an Array or a Hash. The collector defines what the
+ # collect() method is supposed to return.
+ class MessageParameter
+ attr_reader :name
+ attr_writer :multi
+ attr_writer :optional
+ attr_accessor :default
+
+ def initialize(name)
+ self.name = name
+ @multi = false
+ @optional = false
+ @default = nil
+ @regexp = nil
+ @index = nil
+ end
+
+ def name=(val)
+ @name = val.to_sym
+ end
+
+ def multi?
+ @multi
+ end
+
+ def optional?
+ @optional
+ end
+
+ # This method is used to turn a matched item into the actual parameter value.
+ # It only does something when collector= set the @regexp to something. In
+ # this case, _val_ is matched against @regexp and then the match result
+ # specified in @index is selected. As a special case, when @index is nil
+ # the first non-nil captured group is returned.
+ def collect(val)
+ return val unless @regexp
+ mdata = @regexp.match(val)
+ if @index
+ return mdata[@index]
+ else
+ return mdata[1..-1].compact.first
+ end
+ end
+
+ # This method allow the plugin programmer to choose to only pick a subset of the
+ # string matched by a parameter. This is done by passing the collector=()
+ # method either a Regexp with captures or an Array or a Hash.
+ #
+ # When the method is passed a Regexp with captures, the collect() method will
+ # return the first non-nil captured group.
+ #
+ # When the method is passed an Array, it will grab a regexp from the first
+ # element, and possibly an index from the second element. The index can
+ # also be nil.
+ #
+ # When the method is passed a Hash, it will grab a regexp from the :regexp
+ # element, and possibly an index from the :index element. The index can
+ # also be nil.
+ def collector=(val)
+ return unless val
+ case val
+ when Regexp
+ return unless val.has_captures?
+ @regexp = val
+ when Array
+ warning "Collector #{val.inspect} is too long, ignoring extra entries" unless val.length <= 2
+ @regexp = val[0]
+ @index = val[1] rescue nil
+ when Hash
+ raise "Collector #{val.inspect} doesn't have a :regexp key" unless val.has_key?(:regexp)
+ @regexp = val[:regexp]
+ @index = val.fetch(:regexp, nil)
+ end
+ raise "The regexp of collector #{val.inspect} isn't a Regexp" unless @regexp.kind_of?(Regexp)
+ raise "The index of collector #{val.inspect} is present but not an integer " if @index and not @index.kind_of?(Fixnum)
+ end
+
+ def inspect
+ mul = multi? ? " multi" : " single"
+ opt = optional? ? " optional" : " needed"
+ if @regexp
+ reg = " regexp=%s index=%d" % [@regexp, @index]
+ else
+ reg = nil
+ end
+ "<%s %s%s%s%s>" % [self.class, name, mul, opt, reg]
+ end
+ end
+
+ # MessageTemplate is the class that holds the actual message template map()'d
+ # by a BotModule and handled by a MessageMapper
+ #
+ class MessageTemplate
+ attr_reader :defaults # the defaults hash
+ attr_reader :options # the options hash
+ attr_reader :template # the actual template string
+ attr_reader :items # the collection of dynamic and static items in the template
+ attr_reader :regexp # the Regexp corresponding to the template
+ attr_reader :botmodule # the BotModule that map()'d this MessageTemplate