X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=lib%2Frbot%2Firc.rb;h=b8ca459304d453b6e8e183ed656b684a1e7da882;hb=9c50738a84bec26402902513a4cd21b54dcc0a80;hp=31c14802d4aa7c2f83d10cc38ec193b9bf6cb390;hpb=6e0297efd99e34609d6895089e730ce9177c8655;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/lib/rbot/irc.rb b/lib/rbot/irc.rb index 31c14802..b8ca4593 100644 --- a/lib/rbot/irc.rb +++ b/lib/rbot/irc.rb @@ -3,9 +3,11 @@ # * do we want to handle a Channel list for each User telling which # Channels is the User on (of those the client is on too)? # We may want this so that when a User leaves all Channels and he hasn't -# sent us privmsgs, we know remove him from the Server @users list +# sent us privmsgs, we know we can remove him from the Server @users list # * Maybe ChannelList and UserList should be HashesOf instead of ArrayOf? -# See items marked as TODO Ho +# See items marked as TODO Ho. +# The framework to do this is now in place, thanks to the new [] method +# for NetmaskList, which allows retrieval by Netmask or String #++ # :title: IRC module # @@ -19,6 +21,16 @@ require 'singleton' +class Object + + # We extend the Object class with a method that + # checks if the receiver is nil or empty + def nil_or_empty? + return true unless self + return true if self.respond_to? :empty and self.empty? + return false + end +end # The Irc module is used to keep all IRC-related classes # in the same namespace @@ -449,6 +461,13 @@ class ArrayOf < Array } end + # We introduce the 'downcase' method, which maps downcase() to all the Array + # elements, properly failing when the elements don't have a downcase method + # + def downcase + self.map { |el| el.downcase } + end + # Modifying methods which we don't handle yet are made private # private :[]=, :collect!, :map!, :fill, :flatten! @@ -528,7 +547,7 @@ module Irc if self.class == Netmask return self if fits_with_server_and_casemap?(opts) end - return self.fullform.to_irc_netmask(server_and_casemap.merge(opts)) + return self.downcase.to_irc_netmask(opts) end # Converts the receiver into a User with the given (optional) @@ -671,6 +690,35 @@ module Irc super(Netmask, ar) end + # We enhance the [] method by allowing it to pick an element that matches + # a given Netmask, a String or a Regexp + # TODO take into consideration the opportunity to use select() instead of + # find(), and/or a way to let the user choose which one to take (second + # argument?) + # + def [](*args) + if args.length == 1 + case args[0] + when Netmask + self.find { |mask| + mask.matches?(args[0]) + } + when String + self.find { |mask| + mask.matches?(args[0].to_irc_netmask(:casemap => mask.casemap)) + } + when Regexp + self.find { |mask| + mask.fullform =~ args[0] + } + else + super(*args) + end + else + super(*args) + end + end + end end @@ -773,6 +821,21 @@ module Irc end end + # Users can be either simply downcased (their nick only) + # or fully downcased: this will return the fullform downcased + # according to the given casemap. + # + def full_irc_downcase(cmap=casemap) + self.fullform.irc_downcase(cmap) + end + + # full_downcase() will return the fullform downcased according to the + # User's own casemap + # + def full_downcase + self.full_irc_downcase + end + # Since to_irc_user runs the same checks on server and channel as # to_irc_netmask, we just try that and return self if it works. # @@ -780,7 +843,7 @@ module Irc # def to_irc_user(opts={}) return self if fits_with_server_and_casemap?(opts) - return self.fullform.to_irc_user(server_and_casemap(opts)) + return self.full_downcase.to_irc_user(opts) end # We can replace everything at once with data from another User @@ -803,14 +866,24 @@ module Irc # A UserList is an ArrayOf Users + # We derive it from NetmaskList, which allows us to inherit any special + # NetmaskList method # - class UserList < ArrayOf + class UserList < NetmaskList # Create a new UserList, optionally filling it with the elements from # the Array argument fed to it. # def initialize(ar=[]) - super(User, ar) + super(ar) + @element_class = User + end + + # Convenience method: convert the UserList to a list of nicks. The indices + # are preserved + # + def nicks + self.map { |user| user.nick } end end @@ -844,6 +917,7 @@ module Irc # Mode on a Channel # class Mode + attr_reader :channel def initialize(ch) @channel = ch end @@ -856,6 +930,7 @@ module Irc # Example: b (banlist) # class ModeTypeA < Mode + attr_reader :list def initialize(ch) super @list = NetmaskList.new @@ -884,6 +959,11 @@ module Irc @arg = nil end + def status + @arg + end + alias :value :status + def set(val) @arg = val end @@ -901,6 +981,8 @@ module Irc # modes of type A # class UserMode < ModeTypeB + attr_reader :list + alias :users :list def initialize(ch) super @list = UserList.new @@ -927,19 +1009,20 @@ module Irc class ModeTypeC < Mode def initialize(ch) super - @arg = false + @arg = nil end def status @arg end + alias :value :status def set(val) @arg = val end def reset - @arg = false + @arg = nil end end @@ -1159,6 +1242,13 @@ module Irc super(Channel, ar) end + # Convenience method: convert the ChannelList to a list of channel names. + # The indices are preserved + # + def names + self.map { |chan| chan.name } + end + end end @@ -1437,6 +1527,7 @@ module Irc # Checks if the receiver already has a channel with the given _name_ # def has_channel?(name) + return false if name.nil_or_empty? channel_names.index(name.irc_downcase(casemap)) end alias :has_chan? :has_channel? @@ -1444,6 +1535,7 @@ module Irc # Returns the channel with name _name_, if available # def get_channel(name) + return nil if name.nil_or_empty? idx = has_channel?(name) channels[idx] if idx end @@ -1452,9 +1544,15 @@ module Irc # Create a new Channel object bound to the receiver and add it to the # list of Channels on the receiver, unless the channel was # present already. In this case, the default action is to raise an - # exception, unless _fails_ is set to false + # exception, unless _fails_ is set to false. An exception can also be + # raised if _str_ is nil or empty, again only if _fails_ is set to true; + # otherwise, the method just returns nil # def new_channel(name, topic=nil, users=[], fails=true) + if name.nil_or_empty? + raise "Tried to look for empty or nil channel name #{name.inspect}" if fails + return nil + end ex = get_chan(name) if ex raise "Channel #{name} already exists on server #{self}" if fails @@ -1541,6 +1639,7 @@ module Irc # Checks if the receiver already has a user with the given _nick_ # def has_user?(nick) + return false if nick.nil_or_empty? user_nicks.index(nick.irc_downcase(casemap)) end @@ -1554,9 +1653,15 @@ module Irc # Create a new User object bound to the receiver and add it to the list # of Users on the receiver, unless the User was present # already. In this case, the default action is to raise an exception, - # unless _fails_ is set to false + # unless _fails_ is set to false. An exception can also be raised + # if _str_ is nil or empty, again only if _fails_ is set to true; + # otherwise, the method just returns nil # def new_user(str, fails=true) + if str.nil_or_empty? + raise "Tried to look for empty or nil user name #{str.inspect}" if fails + return nil + end tmp = str.to_irc_user(:server => self) old = get_user(tmp.nick) # debug "Tmp: #{tmp.inspect}"