Wednesday, December 10, 2014

7L7W Week 1: Ruby Day 3>40 ct rubies

Hm. Only 3 days? That's not a week; things were just getting interesting.
module ActsAsCsv
  def self.included(base)
    base.extend ClassMethods
  end
  
  module ClassMethods
    def acts_as_csv
      include InstanceMethods
    end
  end
  
  module InstanceMethods
    attr_accessor :headers, :csv_contents

    def initialize
      read
    end

    def read
      @csv_contents = []
      file = File.new(self.class.to_s.downcase + '.txt')
      @headers = file.gets.chomp.split(', ')
    
      file.each do |row|
        @csv_contents << row.chomp.split(', ')
      end
    end
    
    def each
      @csv_contents.each do |row|
        yield(CsvRow.new(@headers, row))
      end
    end

  end
end

class CsvRow
  def initialize(headers, row)
    @data = Hash[headers.zip(row)]
  end
  
  def method_missing name, *args
    puts @data[name.to_s]
  end
end

class RubyCsv
  include ActsAsCsv
  acts_as_csv
end

m = RubyCsv.new
puts m.headers.inspect
puts m.csv_contents.inspect
puts "============================"

class Day3Csv
  include ActsAsCsv
  acts_as_csv
end

m = Day3Csv.new
puts m.headers.inspect
puts m.csv_contents.inspect
puts "----------------------------"

m.each {|row| puts row.one}

It doesn't look like much (and my additions to the book's template are probably quite poorly written or idiosyncratic) but there's some interesting metaprogramming going on. Including ActsAsCsv causes the class method self.included to execute with the including class as the parameter. In this case the including class is extended with the ClassMethods module which defines a single method, acts_as_csv, on the class.

Later in the CsvRow class we include ActsAsCsv and then call the acts_as_csv method. This, I guess, occurs at instantiation which means the specific instance of the CsvRow class gains the InstanceMethods module included by acts_as_csv rather than at the class level though in this case it applies to all instances. The InstanceMethods module defines methods which create the behavior of a CSV file. At multiple points the cascade of includes and method definitions is open to tinkering, conditional method inclusion or definition &etc. It's just gotten interesting, and now this 'week' is done. Maybe I'll study Ruby more later.

No comments: