From: Joe Van Dyk Date: 2005-08-16T04:52:44+09:00 Subject: Re: no clue On 8/15/05, Ara.T.Howard wrote: > On Tue, 16 Aug 2005, Joe Van Dyk wrote: > > > So, say I want to use a class similar to this called > > 'ApplicationData'. The only changes would be the SPEC. > > exactly right. > > > Would the 'ruby way' be to have a base class (say, 'Data'), and then have > > PlayerData and ApplicationData inherit from Data and have them override the > > SPEC? > > i'd personally use a mixin here: > > harp:~ > cat a.rb > module Packable > module ClassMethods > def lazy_attr at, ix > module_eval <<-src > def #{ at } > @#{ at } ||= @data[#{ ix }] > end > def #{ at }= value > raise TypeError unless self.#{ at }.class == value.class > uncache > @#{ at } = @data[#{ ix }] = value > end > src > end > def spec(list=[]) > if list.empty? > @spec > else > @attributes = [] > @format = '' > (@spec = list).each_with_index do |pair, ix| > at, f = pair > @attributes << at > @format << f > lazy_attr at, ix > end > end > end > attr 'attributes' > attr 'format' > def create(*a) > new(a.flatten.pack(format)) > end > end > module InstanceMethods > attr 'data' > def klass > self.class > end > def update buffer > uncache > @data = buffer.unpack klass.format > end > alias initialize update > def uncache > @to_s = @to_bin = nil > end > def to_s > @to_s ||= klass.attributes.inject(''){|s,a| s << "#{ a } : #{ send a }, " }.chop.chop > end > def to_bin > @to_bin ||= @data.pack(klass.format) > end > end > def self::included other > other.extend ClassMethods > other.module_eval{ include InstanceMethods } > end > end > > > class PlayerData > include Packable > > spec [ > %w( pid i ), > %w( x_position f ), > %w( y_position f ), > %w( z_position f ), > %w( foobar i ), > ] > end > > class ApplicationData > include Packable > > spec [ > %w( aid i ), > %w( foobar i ), > %w( barfoo i ), > ] > end > > > pid, x_position, y_position, z_position, foobar = 400, 1.0, 2.0, 3.0, 0b101010 > pd = PlayerData::create pid, x_position, y_position, z_position, foobar > puts pd > > aid, foobar, barfoo = 4, 2, 42 > ad = ApplicationData::create aid, foobar, barfoo > puts ad > > > > harp:~ > ruby a.rb > pid : 400, x_position : 1.0, y_position : 2.0, z_position : 3.0, foobar : 42 > aid : 4, foobar : 2, barfoo : 42 > > > in general class methods and mixins can be combined in an elegant way to > parameterize classes in a way far more flexible than inheritence. Wow... that's really impressive. Thanks again, you've been extremely helpful.