+ 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=%s" % [@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
+
+ # call-seq: initialize(botmodule, template, opts={})
+ #
+ # Create a new MessageTemplate associated to BotModule _botmodule_, with
+ # template _template_ and options _opts_
+ #