On Thu, 28 Aug 2003, Dave Fayram wrote:

> Hi folks,
> My understanding of proper Ruby and duck-typing idoms is still pretty raw, so I
> decided to ask you folks for help.
>
> I'm making a binding to libpcap and libnet for Ruby, which will allow you to do
> non-time-critical network traffic analysis in Ruby. Part of my design was that
> Packet representations will "mix in" their protocols. For instance, a packet
> could be of many different protocols, but still be an IP packet (TCP, UDP,
> custom protocol). Likewise, a packet could be a TCP or UDP packet, but not be
> transmitted via IP. To me, this seems to be an ideal case for mix-ins.
>
> However, this brings up the problem. Sometimes, people will want to know what
> kind of packet a relatively broad filter is spitting back. Is it TCP or UDP? Is
> it IP or ICMP? My first instinct was to just let them check the inclusion
> history. However, recent reading has revealed to me that relying on the class
> and inheritance hierarchy is not the best way to go about doing things in Ruby,
> since things are so dynamic.
>
> What then is the right way to let users of the library I am writing check packet
> type? A method to include symbols seems to me to be a duplication of
> information, which should be avoided. I suppose is_tcp? and is_ip? would be
> viable, but seems inelegant to me.
>
> Am I just being picky, or what? Any suggestions are welcome. Thanks for your
> time!

something like this would allow the various mixins (like TCP) to 'inherit' (via
extend) methods from a 'parent' module (Protocol) and also allow packets to be
'wrapped' in successive protocols in such a way that the type would be
affected correctly. eg:

----CUT----
  class Packet < String
    attr :protocol_stack
    def initialize data
      @protocol_stack = []
    end
    def type
      @protocol_stack
    end
    def wrap(*protocols)
      protocols.map{|protocol| self.extend protocol}
    end
  end

  module Protocol
    def extend_object packet
      raise unless Packet === packet
      packet.protocol_stack << self
    end
  end
  module IP; extend Protocol; end
  module TCP; extend Protocol; end
  module UDP; extend Protocol; end

  a, b, c = %w(a b c).map{|data| Packet.new data}

  a.wrap TCP, IP
  b.wrap TCP, IP
  c.wrap UDP, IP

  p a.type # -> [TCP, IP]
  p b.type # -> [TCP, IP]
  p c.type # -> [UCP, IP]

  p a.type == b.type # -> true
  p b.type == c.type # -> false
  p c.type == a.type # -> false
----CUT----




-a
  ====================================
  | Ara Howard
  | NOAA Forecast Systems Laboratory
  | Information and Technology Services
  | Data Systems Group
  | R/FST 325 Broadway
  | Boulder, CO 80305-3328
  | Email: ara.t.howard / noaa.gov
  | Phone:  303-497-7238
  | Fax:    303-497-7259
  | ~ > ruby -e 'p(%.\x2d\x29..intern)'
  ====================================