title | layout | date | snippet_source |
---|---|---|---|
Super Secret Methods |
post |
2017-07-16 |
code/super_secret_methods.rb |
Here is a quirk of the Ruby language that I discovered a few weeks ago.
Method names can not contain a period character.
{% include_snippet singleton_def_bad %}
This is because the period character is syntax used for defining methods on specific objects.
{% include_snippet singleton_def_ok %}
Even though the syntax does not allow periods in the method name,
surprisingly, the Ruby runtime will allow it.
Using define_method
, the syntax limitations can be bypassed.
{% include_snippet define_method_with_dot %}
The method above can't be called using normal Ruby syntax.
{% include_snippet call_secret_method_bad %}
But again, the syntax limitations can be bypassed, using send
.
{% include_snippet call_secret_method_ok %}
To summarize, it is possible to define and call methods that are impossible to access via normal Ruby syntax.
Upon discovering this, my first thought was "this is a bug in Ruby." My next thought, of course, was "what could I use this for?" The only use that I can think of is avoiding method pollution.
Sometimes, when writing mixins or base classes, you want to define methods for internal use only. You don't want these internal methods to accidentally override or conflict with other peoples' methods.
Roda is very concerned about pollution. [...] Roda purposely limits the instance variables, methods, and constants available in the route block scope, so that it is unlikely you will run into conflicts. If you've ever tried to use an instance variable named @request inside a Sinatra::Base subclass, you'll appreciate that Roda attempts to avoid polluting the scope.
— Roda documentation {:.author}
So this trick can be used to make "secret" methods which don't pollute the namespace of normal methods – although the same trick does not work for instance variables or constants.
{% include_snippet bad_ivar_set %}
{% include_snippet bad_const_set %}
I'm sure someone's already frothing at the keyboard, writing a mean-spirited comment on Reddit, for daring to suggest that this trick might be useful in any way.
So let me be clear: this is probably a bad idea.
I'm still not convinced that it is intended behaviour. I know that method names are allowed to contain unicode, but allowing the period character seems inconsistent to me, since it's not allowed for instance variables or constants.
I also haven't tried it on JRuby, or any other implementations. It might only work on MRI.
It's just an interesting insight into the internals of Ruby.