From: ara.t.howard@... Date: 2006-03-28T01:26:06+09:00 Subject: Re: tagged unions and instantiating objects On Tue, 28 Mar 2006 parisnight@gmail.com wrote: > I frequently work on binary data files that contain data structures > with nested tagged unions: sf2, mp3, smf, CAN, J1939. I can parse the > files ad-hoc and look at data bytes to instantiate the correct final > object but it seems there should be a better classy way where the > parsing occurs hierarchically as the inheriting classes become more > specialized. > > Say a file contains a collection of shapes. As you read bytes you > discover the shapes are squares and triangles, but you don't know that > until you've read some of the data that resides in the shape > superclass, so then you have to pass that data in when you instantiate > the new square object which is then used to assign to instance > variables of the superclass. It would be nicer to be able to > instantiate a generic superclass object, read its data, then based on > the values of the tags specialize the object to become a square or > triangular object and then the specialized object can read its data to > become more specific, and so on. Each child class could parse the bits > it knows about, and the object becomes more specialized as it reads > more. > In CLOS there are ways around this such as described in Peter Seibel's > book. > > Does anyone know of any Ruby techniques that work well when reading > data containing tagged unions? > > Thanks! Bob you want to use something like this pattern: module Type def self.new buf byte = parse_byte buf case byte when 0 TypeA.new buf when 1 TypeB.new buf end end class TypeA ... class TypeB ... end end class TypeB ... end end so Type.new(buf) returns an object of the correct type. each class in the hierachy should be a nested class (though this isn't required). so obj = Type.new(buf) p obj.class # Type::TypeA::TypeB for example i'd highly reccomend using mmap to read/parse the data structure instead of reading the file - this way child classes can have access to the entirety of any previous context required for parsing. using mmap is just like using a string so you can do something like @mmap = Mmap::new path, 'rw', Mmap::MAP_SHARED byte = @mmap[0,1] ... and later, in subclasses if @mmap[12345 .. 12346] == SOME_VALUE if @mmap[0] == SOME_OTHER_VALUE so it saves from doing any explicit io at all and gives easy context to a parser. of course it's also very easy on memory and makes it totally simply to update specific bytes of a binary file without complex seek/set operations. # set a value @mmap[0,4] = [42].pack 'N' regards. -a -- share your knowledge. it's a way to achieve immortality. - h.h. the 14th dali lama