From: ahoward Date: 2003-08-28T04:52:15+09:00 Subject: Re: Design help? Mixins and duck-typing 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)' ====================================