X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=lib%2Frbot%2Fcore%2Futils%2Fextends.rb;h=e62e2f21ea768ec846a7b607020ecaf6c4d9cf73;hb=d4ef91d819164d3a46dc2ce9e4a7ce14b6f5b043;hp=4e5459d850b2493e8435b6b4f545ce836b1c9f4d;hpb=ef60325fc646625ace71030b7ed2b55ff911a9f0;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/lib/rbot/core/utils/extends.rb b/lib/rbot/core/utils/extends.rb index 4e5459d8..e62e2f21 100644 --- a/lib/rbot/core/utils/extends.rb +++ b/lib/rbot/core/utils/extends.rb @@ -4,8 +4,6 @@ # :title: Standard classes extensions # # Author:: Giuseppe "Oblomov" Bilotta -# Copyright:: (C) 2006,2007 Giuseppe Bilotta -# License:: GPL v2 # # This file collects extensions to standard Ruby classes and to some core rbot # classes to be used by the various plugins @@ -38,6 +36,50 @@ class ::Module end +# DottedIndex mixin: extend a Hash or Array class with this module +# to achieve [] and []= methods that automatically split indices +# at dots (indices are automatically converted to symbols, too) +# +# You have to define the single_retrieve(_key_) and +# single_assign(_key_,_value_) methods (usually aliased at the +# original :[] and :[]= methods) +# +module ::DottedIndex + def rbot_index_split(*ar) + keys = ([] << ar).flatten + keys.map! { |k| + k.to_s.split('.').map { |kk| kk.to_sym rescue nil }.compact + }.flatten + end + + def [](*ar) + keys = self.rbot_index_split(ar) + return self.single_retrieve(keys.first) if keys.length == 1 + h = self + while keys.length > 1 + k = keys.shift + h[k] ||= self.class.new + h = h[k] + end + h[keys.last] + end + + def []=(*arr) + val = arr.last + ar = arr[0..-2] + keys = self.rbot_index_split(ar) + return self.single_assign(keys.first, val) if keys.length == 1 + h = self + while keys.length > 1 + k = keys.shift + h[k] ||= self.class.new + h = h[k] + end + h[keys.last] = val + end +end + + # Extensions to the Array class # class ::Array @@ -49,6 +91,40 @@ class ::Array return nil if self.empty? self[rand(self.length)] end + + # This method returns a given element from the array, deleting it from the + # array itself. The method returns nil if the element couldn't be found. + # + # If nil is specified, a random element is returned and deleted. + # + def delete_one(val=nil) + return nil if self.empty? + if val.nil? + index = rand(self.length) + else + index = self.index(val) + return nil unless index + end + self.delete_at(index) + end + + # This method shuffles the items in the array + def shuffle! + base = self.dup + self.clear + while item = base.delete_one + self << item + end + self + end + + # This method returns a new array with the same items as + # the receiver, but shuffled + def shuffle + ret = self.dup + ret.shuffle! + end + end # Extensions to the Range class @@ -137,6 +213,10 @@ class ::String txt.gsub!(/(.*?)<\/sub>/, '_{\1}') txt.gsub!(/(^|_)\{(.)\}/, '\1\2') + # List items are converted to *). We don't have special support for + # nested or ordered lists. + txt.gsub!(/
  • /, ' *) ') + # All other tags are just removed txt.gsub!(/<[^>]+>/, '') @@ -283,5 +363,67 @@ module ::Irc end }.uniq end + + # The recurse depth of a message, for fake messages. 0 means an original + # message + def recurse_depth + unless defined? @recurse_depth + @recurse_depth = 0 + end + @recurse_depth + end + + # Set the recurse depth of a message, for fake messages. 0 should only + # be used by original messages + def recurse_depth=(val) + @recurse_depth = val + end + end + + class Bot + module Plugins + + # Maximum fake message recursion + MAX_RECURSE_DEPTH = 10 + + class RecurseTooDeep < RuntimeError + end + + class BotModule + # Sometimes plugins need to create a new fake message based on an existing + # message: for example, this is done by alias, linkbot, reaction and remotectl. + # + # This method simplifies the message creation, including a recursion depth + # check. + # + # In the options you can specify the :bot, the :server, the :source, + # the :target, the message :class and whether or not to :delegate. To + # initialize these entries from an existing message, you can use :from + # + # If you don't specify a :from you should specify a :source. + # + def fake_message(string, opts={}) + if from = opts[:from] + o = { + :bot => from.bot, :server => from.server, :source => from.source, + :target => from.target, :class => from.class, :delegate => true, + :depth => from.recurse_depth + 1 + }.merge(opts) + else + o = { + :bot => @bot, :server => @bot.server, :target => @bot.myself, + :class => PrivMessage, :delegate => true, :depth => 1 + }.merge(opts) + end + raise RecurseTooDeep if o[:depth] > MAX_RECURSE_DEPTH + new_m = o[:class].new(o[:bot], o[:server], o[:source], o[:target], string) + new_m.recurse_depth = o[:depth] + return new_m unless o[:delegate] + method = o[:class].to_s.gsub(/^Irc::|Message$/,'').downcase + method = 'privmsg' if method == 'priv' + o[:bot].plugins.irc_delegate(method, new_m) + end + end + end end end