+
+ class Factoid
+ def initialize(hash)
+ @hash = hash.reject { |k, val| val.nil? or val.empty? rescue false }
+ raise ArgumentError, "no fact!" unless @hash[:fact]
+ if String === @hash[:when]
+ @hash[:when] = Time.parse @hash[:when]
+ end
+ end
+
+ def to_s(opts={})
+ show_meta = opts[:meta]
+ fact = @hash[:fact]
+ if !show_meta
+ return fact
+ end
+ meta = ""
+ metadata = []
+ if @hash[:who]
+ metadata << _("from %{who}" % @hash)
+ end
+ if @hash[:when]
+ metadata << _("on %{when}" % @hash)
+ end
+ if @hash[:where]
+ metadata << _("in %{where}" % @hash)
+ end
+ unless metadata.empty?
+ meta << _(" [%{data}]" % {:data => metadata.join(" ")})
+ end
+ return fact+meta
+ end
+
+ def [](*args)
+ @hash[*args]
+ end
+
+ def []=(*args)
+ @hash.send(:[]=,*args)
+ end
+
+ def to_hsh
+ return @hash
+ end
+ alias :to_hash :to_hsh
+ end
+
+ class FactoidList < ArrayOf
+ def initialize(ar=[])
+ super(Factoid, ar)
+ end
+
+ def index(f)
+ fact = f.to_s
+ return if fact.empty?
+ self.map { |fs| fs[:fact] }.index(fact)
+ end
+
+ def delete(f)
+ idx = index(f)
+ return unless idx
+ self.delete_at(idx)
+ end
+
+ def grep(x)
+ self.find_all { |f|
+ x === f[:fact]
+ }
+ end
+ end
+
+ # TODO default should be language-specific
+ Config.register Config::ArrayValue.new('factoids.trigger_pattern',
+ :default => [
+ "(this|that|a|the|an|all|both)\\s+(.*)\\s+(is|are|has|have|does|do)\\s+.*:2",
+ "(this|that|a|the|an|all|both)\\s+(.*?)\\s+(is|are|has|have|does|do)\\s+.*:2",
+ "(.*)\\s+(is|are|has|have|does|do)\\s+.*",
+ "(.*?)\\s+(is|are|has|have|does|do)\\s+.*",
+ ],
+ :on_change => Proc.new { |bot, v| bot.plugins['factoids'].reset_triggers },
+ :desc => "A list of regular expressions matching factoids where keywords can be identified. append ':n' if the keyword is defined by the n-th group instead of the first. if the list is empty, any word will be considered a keyword")
+ Config.register Config::ArrayValue.new('factoids.not_triggers',
+ :default => [
+ "this","that","the","a","right","who","what","why"
+ ],
+ :on_change => Proc.new { |bot, v| bot.plugins['factoids'].reset_triggers },
+ :desc => "A list of words that won't be set as keywords")
+ Config.register Config::BooleanValue.new('factoids.address',
+ :default => true,
+ :desc => "Should the bot reply with relevant factoids only when addressed with a direct question? If not, the bot will attempt to lookup foo if someone says 'foo?' in channel")
+ Config.register Config::ArrayValue.new('factoids.learn_pattern',
+ :default => [
+ ".*\\s+(is|are|has|have)\\s+.*"
+ ],
+ :on_change => Proc.new { |bot, v| bot.plugins['factoids'].reset_learn_patterns },
+ :desc => "A list of regular expressions matching factoids that the bot can learn. append ':n' if the factoid is defined by the n-th group instead of the whole match.")
+ Config.register Config::BooleanValue.new('factoids.listen_and_learn',
+ :default => false,
+ :desc => "Should the bot learn factoids from what is being said in chat? if true, phrases matching patterns in factoids.learn_pattern will tell the bot when a phrase can be learned")
+ Config.register Config::BooleanValue.new('factoids.silent_listen_and_learn',
+ :default => true,
+ :desc => "Should the bot be silent about the factoids he learns from the chat? If true, the bot will not declare what he learned every time he learns something from factoids.listen_and_learn being true")
+ Config.register Config::IntegerValue.new('factoids.search_results',
+ :default => 5,
+ :desc => "How many factoids to display at a time")
+