From: Christopher Dicely Date: 2011-05-05T08:22:11+09:00 Subject: Re: Creating variables on an OpenStruct with dynamic names On Wed, May 4, 2011 at 9:34 AM, Jolyon R. wrote: > Hey guys, > > I'm day 3 into The Pragmatic Programmers - Seven Languages in Seven > Days, having previously done a little ruby. I'm from an Actionscript > background and finding Ruby a little challenging, so bear with me. > > I've been parsing some very simple CSV, I've seen there are libraries > out there to handle this, but the book is about learning. > > The book gives us some simple code and the task is to elaborate on 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 > >    attr_accessor :headers, :csv_contents > >    def initialize >      read >    end > >  end > > end > > class RubyCsv  # no inheritance! You can mix it in >  include ActsAsCsv >  acts_as_csv > end > > m = RubyCsv.new > puts m.headers.inspect > puts m.csv_contents.inspect > > The task is to create an *each* method and return a CsvRow object > instead of an array. > > So I figure I need to create the object first in the file.each loop > > This mess is where I got to: > > file.each do |row| >        @headers.each_with_index do |head, index| >          require 'ostruct' >          rowObject = OpenStruct.new >          rowObject.#{@headers[index]} = row.chomp.split(', ') > >        end >        @csv_contents << rowObject >      end > > But as you can see it's a mess I think that (looking at the Day 3 self-study in the book), your best approach will be not to modify any of the "prewritten" methods that you are given: define your CsvRow class first, and make it so that it is something you can populate with the @headers array in ActsAsCsv and one item (row) from @csv_contents. (Pay attention, here, to the book's call to use method_missing!) Then in your new ActsAsCsv#each method, you just need to iterate over the @csv_contents collection, creating and yielding CsvRow objects. I think that's the simplest route to do what you are looking for, and once you've done that bit you can explore variations. You don't need to use OpenStruct (or Struct) -- you could do it with them, but you'll miss out on what the book is getting at with the call to use method_missing.