Search code examples
ruby-on-railsrubydesign-patternsprogramming-languages

How does ruby allow a method and a Class with the same name?


I happened to be working on a Singleton class in ruby and just remembered the way it works in factory_girl. They worked it out so you can use both the long way Factory.create(...) and the short way Factory(...) I thought about it and was curious to see how they made the class Factory also behave like a method.

They simply used Factory twice like so:

def Factory (args)
  ...
end

class Factory
  ...
end

My Question is: How does ruby accomplish this? and Is there danger in using this seemingly quirky pattern?


Solution

  • Methods and variables live in different namespaces. So, you can have both a method and a variable (or in this case a constant) with the same name. However, when using them, Ruby needs to be able to distinguish between them. In general, that's not a problem: messages have receivers, variables don't. Messages have arguments, variables don't. Variables are assigned to, messages aren't.

    The only problem is when you have no receiver, no argument and no assignment. Then, Ruby cannot tell the difference between a receiverless message send without arguments and a variable. So, it has to make up some arbitrary rules, and those rules are basically:

    • for an ambiguous token starting with a lowercase letter, prefer to interpret it as a message send, unless you positively know it is a variable (i.e. the parser (not(!) the interpreter) has seen an assignment before)
    • for an ambiguous token starting with an uppercase letter, prefer to interpret it as a constant

    Note that for a message send with arguments (even if the argument list is empty), there is no ambiguity.

    • test(): obviously a message send, no ambiguity here
    • test: might be a message send or a variable; resolution rules say it is a message send (unless there has been an assignment to test before)
    • Test(): obviously a message send, no ambiguity here
    • self.Test: also obviously a message send, no ambiguity here
    • Test: might be a message send or a constant; resolution rules say it is a constant