Ruby Classes and Class Methods
Posted: 2 years ago (2007-11-13 23:00:59 UTC ) / Updated: 14 months ago (2009-06-01 22:28:03 UTC )
Imported from WordPress
Originally posted on 2007-11-13 23:00:59
If you already understand Ruby's self variable and have a basic grasp of eigenclasses (aka singleton classes, metaclasses and several other things) then you're ready to really understand how Ruby defines methods in a class.
Sadly, this is more complex than it appears.
The easy stuff, using 'def' to define a simple class, is straightforward. But when you ask about the equivalent of static methods (also called class methods), there's more going on than you think. The classic 'static' method is "new". To make a new string, you'd type "myvar = String.new". In Ruby, this is actually a method call defined on the 'String' object. Not an instance of String -- the method is defined on the class object itself. So "new" is defined pretty much (but not quite) like these methods are:
def String.gooey
"Ew! Gooey!\n"
endmyvar = "blah!"
def myvar.gooey
"Yuck, that's all gooey"
endprint String.gooey # prints out "Ew! Gooey!"
print myvar.gooey # prints out "Yuck, that's all gooey"
Remember how Ruby allows you to define a method that's only valid on one specific instance object? "Class methods" or "static methods" are just methods defined on the type object for that class.
"Type object for that class"? That's a weird phrase. Its meaning is strongly related to the fact that you need to capitalize class names when you define them -- just like you capitalize constants. When you make a class, you're really making a constant that points to your new class's class object.
class MyClass
def foo; "foo!"; end
endp MyClass # prints out "MyClass"
p MyClass.class # prints out "Class"
So your new "MyClass" is actually a constant, pointing to an instance of Class. It's as though you had said:
OtherClass = Class.new
OtherClass.class_eval do
def foo; "foo!"; end
end
In fact, it's *exactly* like that. A new class declaration just makes a new object of type Class (if it doesn't already exist) and then does a class_eval in it of whatever you told it to run. Remember, defining a class is just more Ruby code that runs in your class's context.
All of this means that if you did the bit above, but instead of "OtherClass = Class.new" you said "otherclass = Class.new", you'd have a type that wasn't a constant. It's nice to be able to refer to your class by a constant, stable name, but Ruby doesn't actually force you to. If you want to make all of your classes be dynamic, or put them in a big hash table, or use them and then completely lose track of them, that's up to you. Ruby won't stop you.
In fact, though, Ruby class methods are slightly weirder than that. Remember the "String.gooey" example up above? That's actually defined in String's singleton class, because that's what the syntax "def object.function" syntax does. It puts it in the singleton class for "object". And all of that means that if you're running in a method of String, you can't directly see these methods. For instance:
def String.fooblah # A method in String's singleton class
"fooblah!"
endclass String
def my_string_method # A method within String itself
print String.fooblah # this is fine
print fooblah # but this gives an error -- fooblah isn't visible here
end
end
Remember that modules act just like classes through all of this. A Ruby module is basically just a bag of methods that a class can choose to include.
