Finished up day 3 of Ruby a little while ago. The goal was to implement an each method on a provided class which read a csv. The each method was to return each row of the csv as a new CsvRow class. The CsvRow class needed to let you specify object.rowname and get that column value from the row.

So with a csv like this: one, two, three cake, cookies, pie dog, cat, goat

You could do something like:

my_csv = RubyCsv.new()
my_csv.each {|row| puts row.three}

And get the output:

pie
goat

And of course the column names shouldn't matter, so any csv, with any column names would work with no changes to the code. This last requirement was handled with overriding the method_missing() method on the CsvRow object so that calling the row names as methods, which don't exist, would trigger method_missing() and it could figure out what to do.

Here's the full solution how I implemented it:

module ActsAsCsv
  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

    #I added this method
    def each
      @csv_contents.each {|a| yield(CsvRow.new(a,@headers))}
    end

    attr_accessor :headers, :csv_contents

    def initialize
      read
    end
  end
end

class RubyCsv
  include ActsAsCsv
  acts_as_csv
end

#I added this class
class CsvRow
  attr_accessor :row, :headers

  def initialize(row = [], headers = [])
    @row = row
    @headers = headers
  end

  def method_missing(name)
    mysub = name.to_s
    index = @headers.find_index(mysub)
    return @row[index]
  end
end