Friday, May 16, 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!

No comments: