7 Languages in 7 Weeks. Week 1: Ruby Day 3

Mary, Meta

Today Mary Ruby goes Meta. We explored some techniques for using Ruby to create, er, more Ruby.

My previous posts on the 7 Languages in 7 Weeks have been of an unsustainable length so I am going to aim for more succinct offerings for the rest of the exercise.


I confess I’m still waiting for the penny to drop with metaprogramming. To me it still just looks like any other language feature. And yet there are great claims made about it’s utility in re-use and constructing DSLs. The former is clear but the path to the latter is still occluded to me. More examples and applications of it in the wild will hopefully bring me enlightenment.

Metaprogramming is presented as a way of using Ruby to write Ruby. After a mere three days learning the language I find this description unhelpful. Surely we don’t want to get into eval’ing strings of Ruby? And, indeed, none of the samples and exercises we explored went down this road. So what’s up with this description?

What we can do with metaprogramming and Ruby’s open classes is package up code wholly independent of it’s eventual “host object” allowing us to focus completely on the module we are implementing.

The Exercises

We are provided with a simple CSV parsing application and our task is to modify it such that each row is now encapsulated in a new CsvRow object that allows access to each field via method_missing. This will allow us to write the following:

csvParser = RubyCsv.New
csvParser.each do |row|
   puts "Field1 value: #{row.Field1}"

This is my solution to this problem. The latest version can be found on github. The file it uses as input is also available on github.


module ActsAsCsv
  def self.included(base)
    base.extend ClassMethods
  module ClassMethods
    def acts_as_csv
      include InstanceMethods
  module InstanceMethods
    def prepare
      @filename = self.class.to_s.downcase + '.txt'
      File.open(@filename) do |csv_file|
         @headers = csv_file.gets.chomp.split(', ')

    def _read_headers

    def each
       File.open(@filename) do |csv_file|
          csv_file.gets #skip headers
          csv_file.each do |row|
             yield CsvRow.new(@headers, row.chomp.split(', '))
    attr_accessor :headers
    attr :filename
    def initialize



class CsvRow

   attr :row_data

   def initialize(headers, row)
      @row_data = {}
      i = 0
      headers.each do |header|
         @row_data[header] = row[i]
         i += 1

   def method_missing name, *args

class RubyCsv # no inheritance! You can mix it in
  include ActsAsCsv

m = RubyCsv.new
puts m.headers.inspect
m.each do |csvrow|
   puts "one: #{csvrow.one}"
   puts "two: #{csvrow.two}"
   puts "three: #{csvrow.three}"

Teh Codez

As ever the github area for day 3.


2 thoughts on “7 Languages in 7 Weeks. Week 1: Ruby Day 3

  1. I struggle with that definition of “metaprogramming” too. What would you say to the following alternative definition?

    Normal programming is using code to manipulate data.
    Metaprogramming is using code to manipulate code.

    That avoids defining metaprogramming in terms of “writing” code which, as you point out, has connotations of string evaluation.

    • Yeah, that’s definitely better.

      My main issue, that which is frustrating me most, is that I still can’t see what the fuss is about with metaprogramming.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s