Seven Languages in Seven Weeks: Day 3

The emphasis for the final day of Ruby was on metaprogramming using open classes and mixins. So without further ado, here's a CSV reader that provides a mixin that lets you access the values of a CSV file using dynamic properties (Whee!):

module ActsAsCsv
    class CsvRow
        def initialize(csv, fields)
            @fields = fields
            @csv = csv
            @map = Hash[@csv.headers.zip(fields)]
        end

        def method_missing(key)
            @map[key.to_s]
        end
    end

    def self.included(base)
        base.extend ClassMethods
    end

    module ClassMethods
        def acts_as_csv
            include InstanceMethods
        end
    end

    module InstanceMethods
        include Enumerable

        attr_accessor :headers, :csv_contents

        def initialize
            read
        end

        def each
            @csv_contents.each do |row|
                yield row
            end
        end

        def parse(s)
            s.chomp.split(', ')
        end

        def read
            @csv_contents = []
            filename = self.class.to_s.downcase + ".csv"
            file = File.new(filename)
            @headers = parse(file.gets)

            file.each do |row|
                fields = parse(row)
                @csv_contents << CsvRow.new(self, fields)
            end
        end
    end
end

Given a CSV file like this:

msg, response
Hello!, Hi!

... we could read it like this:

class Example
    include ActsAsCsv
    acts_as_csv
end

Example.new.each do |row|
    puts row.msg, row.response
end

Seven Languages in Seven Weeks: Day 2

A grep work-a-like which despite being much shorter then the previous exercise actually has the possibility of being useful:

pattern = Regexp.new(ARGV[0])
path = ARGV[1]

File.open(path, "r").each_with_index do |line, i|
    puts "#{path}:#{i + 1}\t#{line}" if line.index(pattern)
end

Seven Languages in Seven Weeks: Day 1

I picked up Seven Languages in Seven Weeks after Martin Fowler recommended it. After half an hour of reading I wrote one whole Ruby program!

i = rand(10)

puts "I'm thinking of a number x ∈ [0,9]. Can you guess it?"

while true do
    print ">> "
    guess = gets.to_i

    break if guess == i
    puts "Too low." if guess < i
    puts "Too high." if guess > i
end
puts "Good job :-)"

(I may have known a little bit of Ruby before I started ;-).

With Statement (Redux)

My previous implementation of the with_statement in ruby had one major flaw: It allowed only a single context manager per with block. While effective, it leads to cluttered code, like the following:

with(open("hello.txt")){|f|
    with(open("bonjour.txt")){|g|
        puts f.read()
        puts g.read()
    }
}

Effective, but it isn't as clear as it could be and introduces more nesting than is really necessary. This coupled with my desire to explore varargs methods and blocks in ruby has lead me to a more robust implementation that can take an arbitrary number of managers as a parameter.

def with(*managers, &block)
    def with_(managers, resources, block)
        if managers.nitems > 0
            begin
                resource = managers.delete_at(0)
                resources << resource.enter()
                with_(managers, resources, block)
            ensure
                resource.exit()
            end
        else
            block.call(*resources)
        end
    end

    with_(managers, [], block)
end

The preceding implementation is more complex than the original. In addition to introducing "star magic"1, it relies on recursive creation of begin-ensure blocks which complicates exception handling; however, this implementation allows for such beautiful usage as:

with(open("hello.txt"), open("bonjour.txt")) {|f, g|
    puts f.read()
    puts g.read()
}

Should a manager's exit method raise an exception, that exception will supersede any exception raised within the block, though it will not interfere with exiting other managers.

An implementation and unittests are available in a Mercurial repository. The implementation can be retrieved as follows:

hg clone http://hg.crimzon.ath.cx/with_statement

Both the implementation and unittests are licensed under the MIT license.

[1]As it is called by pylint.

With Statement in Ruby

One of the things that I do enjoy about Ruby is the ability to use blocks to synthesize control structures that may be missing. For instance, I'm a big fan of python's with statement. Through a combination of guerilla patching and blocks, the with statement can easily be added to the ruby language as a library.

require 'thread'

class Mutex
    def enter
        lock
    end

    def exit
        unlock
    end
end

class IO
    def enter
        return self
    end

    def exit
        close
    end
end

class ContextManager
    def enter
    end

    def exit
    end
end

def with(resource)
    begin
        yield(resource.enter())
    ensure
        resource.exit()
    end
end

This implementation allows for such beautiful usage as:

require 'thread'
require 'with_statement'

with(File.open("hello.txt")) {|f|
    puts f.read()
}

lock = Mutex.new
with(lock){
    puts "Yay! Synchronized!"
}