Charlie Harvey

Ruby — Day Three

The last day is definitely the most fun. We get to play with metaprogramming with one bigger question, of which more shortly. My reflections on Ruby were it was cool to catch up with the language. I’d sort of forgotten quite how nifty it was to play with. For my money its more Perlish than the other popular OO scripting language Python, which is a very good thing in my book. Perhaps, I’ll make something with Ruby rather than Perl next time I’m hacking a project, who knows?

The next language is Io. Unlike Ruby I have not even touched Io before. So I anticipate a bit more of a challenge. I will probably make a start some time next week. To give my brain a bit of a rest. And to recover my poor social life a bit ;-)

acts_as_csv.rb

Modify the CSV application to support an each method to return a CsvRow object. Use method_missing on that CsvRow to return the value for the column for a given heading.

I shall have a trawl around to see how other folks did this. I’m not so happy with the nested loop in the read method. I just extended Hash to make my CsvRow object. It does most of what I want, I got a bit stuck on the method_missing syntax but Code friendly hashes in Ruby with method_missing on agile advisor helped me see things were way less difficult than I’d imagined.

My data file was: one, two, three chips, beans, mushrooms cider, lager, vodka techno, gabba, house

My code was: #!/usr/bin/ruby module ActsAsCsv # A CsvRow is basically a Hash keyed on the column name innit? class CsvRow < Hash def method_missing(name) return self[name.to_s] end end 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 + '.csv' f = File.new(filename) @headers = f.gets.chomp.split(', ') rowcount = 0 f.each do |row| cellcount = 0 row.chomp.split(', ').each do |cell| if @csv_contents[rowcount] == nil @csv_contents[rowcount] = CsvRow.new end @csv_contents[rowcount][@headers[cellcount]] = cell.chomp cellcount = cellcount + 1 end rowcount = rowcount + 1 end end attr_accessor :headers, :csv_contents, :csv_rows def initialize read end def each @csv_contents.each do |row| yield row end end end end class RubyCsv include ActsAsCsv acts_as_csv end r = RubyCsv.new r.each {|row| puts row.one}

Running it produces: $ ./acts_as_csv.rb chips cider techno $


Comments

  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.