Ruby spreadsheet hack for whyday

Like many others, my introduction to ruby was Why’s (poignant) guide to ruby. Why’s attitude towards programming emphasized fun, learning, and creativity above generally regarded “best practices”.

On august 19th, the Ruby community throws caution and best practices to the wind to celebrate Whyday.

I hoped to capture this programming spirit with this ~30 line Spreadsheet class which can have procs as cells. This is adapted from an idea I’ve seen a couple times in python. It supports access through array both array access (ss['a0']) and methods (ss.a0), ranges (ss.a[0..10]) are also supported.

class Spreadsheet
  def initialize
    @hash =
  class Subset <, :row, :col)
    def [] k
      return{|x| self[x]} if k.respond_to? :map
      spreadsheet[cell k]
    def []= k, v
      return{|x| self[x] = v} if k.respond_to? :map
      spreadsheet[cell k] = v
    def cell k; "#{self.col || k}#{self.row || k}"; end
  def method_missing cell, *args
    if cell =~ /\A([a-z]+)([0-9]+)=\Z/
      @hash[[$1, $2]] = args.first
    elsif cell =~ /\A([a-z]+)([0-9]+)\Z/
      v = @hash[[$1, $2]]
      v.is_a?(Proc) ? self.instance_eval(&v) : v
    elsif cell =~ /\A([a-z]+)\Z/, nil, $1)
    elsif cell =~ /\A_?([0-9]+)\Z/, $1, nil)
  def []= key, value; method_missing("#{key}=", value); end
  def []  key;        method_missing(key.to_s); end
  def to_s; @hash.to_s; end

ss =

ss.a1 = { a2 + a3 }
ss['a'][2..10] = 50   # assign a2 through a10
puts ss.a1
# => 100
ss['a']['1'] = { a[2..20].inject(:+) }
puts ss['a1']
# => 450
ss.b1 = 'hello, world'
ss.d[1..20] = 'chunky bacon'
puts ss['1']['a'..'e'].inspect  # print a1 through e1
# => [450, "hello, world", 0, "this fills row d", 0]

Hope you enjoyed.