From: Alex Fenton Date: 2006-09-09T20:10:23+09:00 Subject: Re: How to read and write 80 column punched cards with Ruby Christer Nilsson wrote: > I'm trying to communicate with a bank. Banks are still using the punched > card layout in their files. > > Example: 001234567800023420060909 > (account=12345678, amount=234 and day=20060909) > I would like to define the class like this (compare attr) > > class Trans < Record > field :account, 10 > field :amount, 6 > ... You're on the right lines, but in your example you're working with instance methods when you want to work with class methods. Define a 'field' *class* method in the Record class, which defines reader and writer *instance* methods. Something like below. Tip - don't use method_missing unless you really have to; there is often another way, e.g. define_method. Some well-known libraries do it but it really screws up debugging and reflection, and makes method dispatch even slower. hth alex ___ class Record class Field attr_accessor :name, :length, :position def initialize yield self end end def Record.field(field_name, field_length) @fields ||= [] position = @fields.inject(0) { | sum, f | sum += f.length } @fields << Field.new do | f | f.name, f.length, f.position = field_name, field_length, position end attr_reader field_name define_method("#{field_name}=") do | value | value = value.to_s.rjust(field_length, '0') instance_variable_set("@#{field_name}", value) end end def Record.fields @fields end def initialize(str) self.class.fields.each do | field | send("#{field.name}=", str[field.position, field.length]) end end def to_s self.class.fields.inject('') { | str, f | str << send(f.name) } end end class Transaction < Record field :account, 10 field :amount, 6 field :lastday, 8 end trans = Transaction.new("001234567800023420060909") puts trans # 001234567800023420060909 puts trans.amount.to_i # 234 trans.amount = 120 puts trans # 001234567800012020060909