16 May 2008
In the Spirit of Brevity, class_attr Methods

Ruby is the language for coding brevity with elegance. The more you “get” Ruby, the less code you end up writing. One of the ways you do this is to just metacode the things you find yourself doing a lot and become more productive. And that’s a beautiful thing!

Recently, I’ve found myself writing and rewriting class attribute accessors, like

class Foo
  def self.bar
    @@bar
  end
  def self.bar=(bar)
    @@bar = bar
  end
end

Being from the old school, while I’m not adverse to just using the @@ directly inside the class, I prefer some encapsulation. And when you want to expose the class’ innards, you need to write these methods anyway. This if fine, but it gets a bit too verbose for me.

Instance attributes are exposed easily with the attr methods

class Mumble
  attr_accessor :barfle
end

which creates the barfle and barfle= instance methods. What I want is an analogous

class Foo
  class_attr_accessor :bar
end

to create my self.bar and self.bar= methods. Metaprogramming to the rescue!

class Module
  def class_attr_reader(*kattrs)
    kattrs.each { |kattr|
      ka = kattr.to_s
      reader = <<EOS
def #{ka}
  @@ka
end
EOS
      self.module_eval reader
    }
  end

  def class_attr_writer(*kattrs)
    kattrs.each { |kattr|
      ka = kattr.to_s
      writer = <<EOS
def self.#{ka}=(#{ka})
  @@#{ka} = #{ka}
end
EOS
      self.module_eval writer
    }
  end

  def class_attr_accessor(*kattrs)
    class_attr_reader(*kattrs)
    class_attr_writer(*kattrs)
  end
end

Sweetness. I just love Ruby!