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:
-
Does the syntax appear to be in line with the community standards?
-
Are my uses of class_eval and instance_eval okay / is there a better
way? -
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. -
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 G.
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