Have you ever been confused by the __underscores__ required by some of __RUBY__'s features? You can get it right with this overview of all of "super snake" keywords and methods.
There are three different types of underscore-wrapped syntaxes in the Ruby core language:
- keywords
- Object methods and
- Kernel methods.
Let us take a look at each of them, and understand the motivations behind. Or directly jump to:
__FILE____LINE____ENCODING____END____method____callee____dir____id____send__
Keywords (Built into Ruby Syntax)
These are directly translated by the Ruby interpreter: You cannot use meta-programming with these, since they will always return the corresponding value directly:
__FILE__
Returns the current source file's name. Might be special value for unusual invocations:
Context | Value |
---|---|
File, directly executed | path name, can be relative |
File, required / loaded | absolute path |
IRB | "(irb)" |
eval'd | "(eval)" |
$ ruby -e |
"-e" |
Standard Input | "-" |
__LINE__
Returns the line number in the current source file. Also works in IRB and with code executed with $ ruby -e
, STDIN or eval
.
__ENCODING__
Returns the source file's encoding, as specified per magic comment. The default source file encoding is UTF-8. The important thing to understand is that this value should correspond to the actual encoding of the source file, so to change the source encoding, it is not enough to just change the magic comment, you will also need to convert the source file.
You should also note that this is unrelated to some other global encoding configurations, which serve different purposes:
__END__ (at beginning of line)
A special syntax which will end the source file earlier and create big data.
Underscore-Wrapped Kernel
Methods
These special Kernel methods are lowercased to highlight the fact that they are actually just methods and no built-in keywords.
__method__ and __callee__
Both return the current method's name, but they differ in a detail: When using a method alias, __callee__
will return the aliased method name, while __method__
would return the original name:
def example!
p [__method__, __callee__]
end
alias test! example!
example! # => [:example!, :example!]
test! # => [:example!, :test!]
Two similar and useful methods are Kernel#caller and Kernel#caller_locations, which provide some more context.
__dir__
Returns File.dirname(File.realpath(__FILE__))
, which is the absolute path of the directory of the current source file.
While it also works in IRB, it will return nil
in eval, $ ruby -e
, and STDIN contexts.
Underscore-Wrapped BasicObject
Methods
Both of the following methods are so important that every object (even those that inherit from BasicObject directly) should have. This is why they got some underscore companions.
__id__
Returns the object id, just like Object#object_id. It mainly exists for historical reasons, most people use object_id
nowadays.
__send__
The __send__
method is an alias of the Object#send, which dynamically calls the method given as a symbol argument. Its purpose is that you should still be able to use the send functionality in case someone redefines the send
method. The interpreter will issue a warning¹ should you try to redefine or remove it:
warning: redefining `__send__' may cause serious problems
Nevertheless, it is probably not a good idea either to redefine non-underscore-wrapped send
, since a lot of meta-programming relies on it…
¹ This is not true for __id__
- Ruby will not complain if you choose to redefine it. It will complain for object_id
though.
Also See
- Episode 5: Constant Shadows (even another way Ruby uses underscores)
- Episode 19: Symbolic Reservations (in certain cases, symbols with underscores can be special)
Many thanks to Shannon Skipper for pointing out that the mysterious SUPPORT_JOKE
compiler option's __goto__
and __label__
also make use of underscores
More Idiosyncratic Ruby
- Please Comment on GitHub
- Next Article: Ruby TRICKS of 2018
- Previous Article: Unicode Version Mapping