I finished the Ruby chapter in Seven Languages in Seven Weeks. It tries to make you familiar with the core concepts of several languages rather quickly. Dutifully I did all exercises, but most likely they can be improved to be more Ruby-like.
Given: a CSV file structured with a first line with headers and subsequent rows with data.
one, two lions, tigers
Create a module which loads the header and values from a CSV file, based on the name of the implementing class. (RubyCSV -> "rubycsv.txt") Support an
each
method which returns aCsvRow
object. Usemethod_missing
to return the value for the column for a given heading. E.g. usage which will print "lions":m = RubyCsv.new m.each { |row| p row.one }
My implementation:
class CsvRow
attr :row_hash
def initialize( row_hash )
@row_hash = row_hash
end
def method_missing( name, *args )
@row_hash[ name.to_s ]
end
end
module ActsAsCsv
attr_accessor :headers, :csv_contents
def self.included( base )
base.extend ClassMethods
end
module ClassMethods
def acts_as_csv
include InstanceMethods
end
end
module InstanceMethods
def read
@csv_contents = []
filename = self.class.to_s.downcase + '.txt'
file = File.new( filename )
@headers = file.gets.chomp.split( ', ' )
file.each do |row|
@csv_contents << row.chomp.split( ', ' )
end
end
def initialize
read
end
def each
@csv_contents.each do |content|
hash = {}
@headers.zip( content ).each { |i| hash[ i[0] ] = i[1] }
yield CsvRow.new hash
end
end
end
end
class RubyCsv # No inheritance! You can mix it in.
include ActsAsCsv
acts_as_csv
end