From: 7stud -- Date: 2011-05-05T10:58:50+09:00 Subject: Re: Creating variables on an OpenStruct with dynamic names Jolyon R. wrote in post #996621: > 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. > Then I wouldn't worry too much about Jesús Gabriel y Galán's code because it contains some advanced stuff. > > 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. > Typically, you call an each() method like this: obj.each do |x| puts x end That syntax uses what's called a 'block', which is this part: do |x| puts x end The block tells the each() method to iterate over the elements of obj, and send them to the block one by one. The element will get assigned to the parameter variable x of the block. In order for the each() method to send elements to the block, each() must call the yield() function. Here is an example: class Dog def each yield 'dog' yield 20 yield 'last one' end end d = Dog.new d.each do |x| puts x end --output:-- dog 20 last one In your case, you will be iterating over the lines of a file. To me it seems like you need to organize your code along these lines: class RubyCsv # no inheritance! You can mix it in include ActsAsCsv def initialize(fname) @file = File.new(fname) end def each yield RowObject.new(@file.gets) end end class RowObject attr_reader :fields def initialize(line) @fields = line.chomp.split(', ') end end Note that initialize() opens the file, so somewhere you will need to close the file. -- Posted via http://www.ruby-forum.com/.