Saturday, October 20, 2007
Ruby: Defining Class Methods
There are several ways to define class methods in Ruby.
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.
I prefer this version. The syntax is concise and descriptive. When browsing a file of code, the use of
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
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.
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).
...
end
endThis 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.
...
end
endI 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.
protected
...
end
end
endThis 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
# http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
name, &blk
(class << self; self; end).instance_eval {define_method name, &blk }
end
end
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 # => 23This 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.
instance_eval do
...
end
end
endIt'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).
Labels: class methods, ruby
Comments:
<< Home
It looks mightily confusing when the syntax highlighting has hidden the underscores in "meta_def" and "instance_eval". For a minute I thought there was some trick I wasn't aware of, but the html source revealed that there indeed are underscores in both.
Hi Jay,
One other way could be putting your methods in a module and then in your class : extend ClassMethods
If you're looking for a better way for your readers to submit code may I suggest cross-posting to http://refactormycode.com/ and using the trackback feature.
One other way could be putting your methods in a module and then in your class : extend ClassMethods
If you're looking for a better way for your readers to submit code may I suggest cross-posting to http://refactormycode.com/ and using the trackback feature.
Two more class_eval examples are http://snippets.dzone.com/posts/show/3378 and http://snippets.dzone.com/posts/show/2786
I prefer the singleton class way. Something about seeing 'def self.' over and over gets to me, but then again I try to use self as a receiver only when necessary.
It also lets you do other things more naturally, like declaring some methods private (not protected, since that doesn't make sense for a class method), and creating aliases.
It also lets you do other things more naturally, like declaring some methods private (not protected, since that doesn't make sense for a class method), and creating aliases.
Hi Jay, I somehow seem to remember that the Person.class_meth form used to bomb when invoked via a subclass (sample code below). I tried it on Ruby 1.8.6 and it doesn't bomb anymore. Did it ever bomb in a previous Ruby version or am I day-dreaming??
Eg:
class Person
def Person.my_class_meth
"hi"
end
def self.another_class_meth
"bye"
end
end
class Employee < Person
end
Employee.my_class_meth # Did this ever bomb with undefined method?!
Employee.another_class_meth # This always worked
Eg:
class Person
def Person.my_class_meth
"hi"
end
def self.another_class_meth
"bye"
end
end
class Employee < Person
end
Employee.my_class_meth # Did this ever bomb with undefined method?!
Employee.another_class_meth # This always worked
As far as I know it always worked, but since I don't use that form I'm not the authority on it.
On my first project we used Ruby 1.8.4 and it seemed to work fine...
On my first project we used Ruby 1.8.4 and it seemed to work fine...
Another drawback of the first form which the others avoid is that the class name occurs multiple times in the source for the class definition. If it needs to be changed for any reason (e.g. you realise it was a bad choice, or you want to clone the class as a start-point for a similar one) it has to be changed in multiple places. Not a huge effort, but irksome.
Post a Comment
<< Home




