Seven Languages in Seven Weeks: Day 3
The emphasis for the final day of Ruby was on metaprogramming using open classes and mixins. So without further ado, here's a CSV reader that provides a mixin that lets you access the values of a CSV file using dynamic properties (Whee!):
module ActsAsCsv
class CsvRow
def initialize(csv, fields)
@fields = fields
@csv = csv
@map = Hash[@csv.headers.zip(fields)]
end
def method_missing(key)
@map[key.to_s]
end
end
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def acts_as_csv
include InstanceMethods
end
end
module InstanceMethods
include Enumerable
attr_accessor :headers, :csv_contents
def initialize
read
end
def each
@csv_contents.each do |row|
yield row
end
end
def parse(s)
s.chomp.split(', ')
end
def read
@csv_contents = []
filename = self.class.to_s.downcase + ".csv"
file = File.new(filename)
@headers = parse(file.gets)
file.each do |row|
fields = parse(row)
@csv_contents << CsvRow.new(self, fields)
end
end
end
end
Given a CSV file like this:
msg, response
Hello!, Hi!
... we could read it like this:
class Example
include ActsAsCsv
acts_as_csv
end
Example.new.each do |row|
puts row.msg, row.response
end