Alex Fenton
9/9/2006 11:10:00 AM
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