Question

I tried to capture undefined methods by the following definition:

def method_missing m
  puts "#{m} is missing"
end

When I write an undefined method such as foo after it, it is captured by method_missing:

foo # => foo is missing

but when I write an undefined method such as Foo, it is not captured by method_missing:

Foo # => NameError: Uninitialized constant Foo

It looks like if it is disambiguated from a constant, then it is captured:

self.Foo # => Foo is missing
Foo() # => Foo is missing

Why is Foo not captured in the first case? Is it a feature that when a method is ambiguous between a local variable, it is captured by method_missing, but not when it is ambiguous between a constant? If so, is there documentation on this? Or, is it a bug?

Was it helpful?

Solution

The thing is that this actually isn't ambiguous — it's just not intuitive. In Ruby's grammar, an identifier that starts with a capital letter and isn't followed by an argument list is always parsed as a constant lookup.

You would get the same error even if you had defined a method like def Foo "You won't see this" end. When it encountered Foo, it would still try to look up the constant Foo and throw a NameError when no constant by that name was found. In order to call a method that starts with a capital letter, you have to include an explicit receiver (e.g. self.Foo) or an argument list (if only an empty one).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top