Saturday, October 20, 2007

Ruby: Defining Class Methods

There are several ways to define class methods in Ruby.

class Person
def Person.find(id)
...
end
end

This is the version that recent Java/C# converts seem to prefer. I'm not a big fan of this version because it requires me to change all the class method definitions if I change the name of the class.

class Person
def self.find(id)
...
end
end

I prefer this version. The syntax is concise and descriptive. When browsing a file of code, the use of self. makes it very clear that the method is a class method. This is the version I use by default.

class Person
class << self
protected
def find(id)
...
end
end
end

This is the version I use when I need to make the method protected. For more information on why this is necessary you can check my previous entry: Protected Class Methods

class Object # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
def meta_def name, &blk
(class << self; self; end).instance_eval { define_method name, &blk }
end
end

class Service
def self.responses(hash)
hash.each do |method_name, result|
meta_def method_name do
result
end
end
end

responses :success => 20, :unreachable => 23
end

Service.success # => 20
Service.unreachable # => 23

This version is by far the most complicated to write and read. The justification for using this version is that you can create class methods that declaratively define other class methods. This version requires the use of define_method instead of def because variables from the surrounding context are necessary. I tend to only use this version when I'm metaprogrammatically defining other class methods.

class Person
instance_eval do
def find(id)
...
end
end
end

It's also possible to define class methods inside an instance_eval sent to a class. For an explaination of why this works check out instance_eval and class_eval method definitions. As the linked entry states, I have run into this by accident, but I don't think I've ever actually used instance_eval to define class methods on purpose.

Are there ways that you define class methods that I've left off. If so, please let me know how and why in the comments (with an explanation inline or a link to a blog post on your site).
Post a Comment