? and ! are only allowed as method suffixes in ruby

Ruby method names can contain a question mark or an exclamation point,
but it must be the last character. So foo? and foo! are fine, but
foo?bar and foo!bar are not.

This does not seem like a big deal until you run into code that assumes
that it can add characters to the end of any method name. For example,
Ruby Facets has a method called cache
which allows the user to ensure a method is called once and only once
per instance. You can see the code and comments in the Facets SVN
Repository
.

For example, the following code will only print bar once:

def foo
  puts "bar"
end
cache :foo

foo
foo

cache is implemented by aliasing the original method and redefining it.
The new version checks a hash to see if it has already been called. The
aliasing is done with the line:

alias_method '__#{ m }__', '#{ m }'

So a method called:

foo

will be aliased to:

__foo__

This will fail if the method ends in a ? or ! since it cannot append
__ to the end of the method name.

This is a subtle bug to track down. The error is cryptic, since the ruby
parser fails when it reaches the trailing underscores. Furthermore, the
code doesn’t fail until the method is called, not when the caching is
done:

def foo?
  true
end
cache :foo?

>> foo?
NoMethodError: undefined method `__' for #<Object:0xb7cc99f0 @cache={"foo?"=>{}}>
        from (eval):8:in `foo?'
        from (irb):34

A better way to redefine methods is to unbind and rebind them. This
technique is explained nicely in Jay’s blog: Ruby: Alias method
alternative

Paul Gross

Paul Gross

I'm a lead software developer in Seattle working for Braintree Payments.

Read More