Ruby Day 3: Serious change
The final day on Ruby is all about metaprogramming. It takes you through:
- Adding methods to open classes
- Using method missing to produce very human readable syntax
- Adding functionality to classes via Modules
Having used Java reflection, Java IDL Dynamic Invocation Interface (DII) and the Java IDL Dynamic Seketon Interface extensively when I used to develop IBM's Websphere Message Broker I know how cumbersome any form of metaprogramming is in Java. So I enjoyed playing around with a language that does it much better!
Now to the Self study. Only one this time! Modify the Csv application to support an each method to return a CsvRow object. E.g for the following csv file:
one, two
lions, tigers
allow an API that works like this:
csv = RubyCsv.new
csv.each{|row| puts row.one}
This should print "lions".
Well I decided to work with the following input:
one, two, three
1, 2, 3
uno, dos, tres
And here is my solution using modules and method missing:
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
def each(&block)
@csv_contents.each_index do |index|
hash = Hash[@headers.zip @csv_contents[index]]
block.call(CsvRow.new(hash))
end
end
end
attr_accessor :headers, :csv_contents
def initialize
read
end
end
class RubyCsv
include ActsAsCsv
acts_as_csv
end
class CsvRow
def initialize(arg)
@arg = arg
end
def method_missing name, *args
key = name.to_s
return @arg[key]
end
end
m = RubyCsv.new
m.each do |row|
puts row.send(ARGV[0])
end
And that is it for Ruby!
No comments:
Post a Comment