From: Dave Thomas Date: 2003-06-28T01:38:47+09:00 Subject: Re: Magic at class-definition time Clifford Heath wrote: > There's a few things I don't get about Dave's example though, so > perhaps he or someone else would explain? > > I'm guessing that "field" defines methods for the current class > instance. In this case does "field" have to eval a string with > the method definition in it or is there a better way? That's how I did it: def Table.field(type, name, *options) f = Field.new(name, type, options) @fields << f @primary_key = f if f.primary_key? create_accessors_for(f) create_writer_for(f) end def Table.create_accessors_for(field) name = field.name class_eval <<-EOS def #{name} @#{name} end def #{field.setter_name}(val) @#{name} = val#{field.type.conversion_function} end EOS end def Table.create_writer_for(field) name = field.name class_eval <<-EOS def #{name}=(val) set_changed(:#{name}) if val != @#{name} @#{name} = val end EOS end > > Why did Dave call "field" from a block attached to "table", instead > of just from the class RegionTable? It gives me some encapsulation of the generation of the table-specific stuff, and it seemed neat at the time. For example, more complex table classes have extra code in there: class StateNameTable < Table Suspended = 'SUSPND' WaitPayment = 'WTPAY' Active = 'ACTIVE' table "state_name" do field char(6), :stt_id, pk field varchar(30), :stt_desc initial_values([Suspended, "Inactive"], [WaitPayment, "Not paid"], [Active, "Active"] ) end end In the end, I could do it without the yield, but I like the way that doing it allows me to know when the definition is finished, and hence generate all the accessors. I can see I'm going to have to write this up at some point... :) Cheers Dave