I finally decided to dive in and give metaprogramming in Ruby a shot. I'm
not sure that my example is exactly practical, but it seemed useful at the
time. There's a few areas I would like to hear others suggestions on:
1. Does the syntax appear to be in line with the community standards?
2. Are my uses of class_eval and instance_eval okay / is there a better way?
3. I am using facets because I like the Dictionary (OrderedHash), but I'm
sure there are better ways to build the structure while preserving the field
order. I especially don't like the fact that I have to specify Dictionary[]
in the structure of the subclass.
4. Please comment on the code in general, I'm open to any kind of criticism.
I'm not sure if it's customary to attach the code in a file or post it in
the email. I apologize if I should have attached the code in a file.
Michael Guterl
···
----------------------------------------------
require 'rubygems'
require 'facets'
require 'dictionary'
class FixedLength
def self.structure(ordered_hash)
class_eval do
@@structure = ordered_hash
end
keys = @@structure.keys
instance_eval do
attr_accessor *keys
end
end
# this entire method could probably be a lot cleaner
def self.open(file_name)
class_eval do
data = IO.read(file_name)
records = []
data.each_line do |line|
last_position = 0
record = self.new
@@structure.each_pair do |name, length|
record.instance_variable_set( "@#{name.to_s}",
line.slice(last_position,
length.to_i).strip)
last_position += length.to_i
end
records << record
end
return records
end
end
end
class InputStructure < FixedLength
# I'd like to clean this up, either removing the need for Dictionary[] and
the separation by commas
# or with something like this
# column.add :id, 10
# column.add :phone, 10
# column.add :first_name, 25
# etc. I'd love to hear some suggestions.
structure Dictionary[ :id , 10,
:phone , 10,
:first_name , 25, :middle_name , 1, :last_name , 25,
:address , 30,
:city , 25,
:state , 2,
:zip , 5, :zip4 , 4 ]
end
require 'test/unit'
class InputStructureTest < Test::Unit::TestCase
def setup
@records = InputStructure.open('fixed_data.txt')
end
def test_first
record = @records.first
assert_equal "1", record.id
assert_equal "1234567890", record.phone
assert_equal "SOME RANDOM", record.first_name
assert_equal "", record.middle_name
assert_equal "PERSON", record.last_name
assert_equal "1234 SOME RANDOM STREET", record.address
assert_equal "RANDOM CITY", record.city
assert_equal "OH", record.state
assert_equal "45219", record.zip
assert_equal "", record.zip4
end
end