Kernel#__method__
__method__ Kernel#__method__ returns the name of the method in which it is called, as a Symbol. It is defined on Kernel, inherited by every object, and has been stable since Ruby 1.8.7.
It is the simplest answer to the question “what method am I in?” and shows up most often in logging, in method_missing handlers, and in code that forwards the current method name as data.
A typical logging use:
def calculate_total(cart)
started_at = Time.now
result = cart.sum { |item| item.price }
warn "[#{__method__}] processed #{cart.size} items in #{Time.now - started_at}s"
result
end
The interpolated #{__method__} becomes :calculate_total, so the log line tags itself without a manual string.
Signature at a glance
| Property | Value |
|---|---|
| Defined in | Kernel (private instance method) |
| Receiver | ignored; usually called with no explicit receiver |
| Arguments | none |
| Return type | Symbol |
| Available since | Ruby 1.8.7 |
| Status | not deprecated |
Calling it with arguments raises ArgumentError. Because it is private, the conventional call is just __method__, not obj.__method__.
Return value in a normal method
The symbol is the method’s name as it was defined, regardless of how the call was spelled.
def greet
__method__
end
greet # => :greet
__method__ does not care whether you used parens, a space, or a send. It always resolves to the lexical name of the enclosing method definition.
method versus callee
The interesting behaviour appears with alias_method and the alias keyword. The alias becomes a new entry point, but the body still belongs to the original method.
class Logger
def write
__method__
end
alias_method :emit, :write
end
Logger.new.emit # => :write
__callee__ exists precisely for the entry point. Where __method__ resolves to the original method that defined the body, __callee__ resolves to whatever alias or original was actually invoked. Logging both gives you the implementation name and the call site without an extra argument.
class Box
def store
[:method, __method__, :callee, __callee__]
end
alias_method :put, :store
end
Box.new.put
# => [:method, :store, :callee, :put]
If your code dispatches on the call site (to pick a log level, a metric tag, or a branch), reach for __callee__. If you want the name of the code that is actually running, use __method__.
Inside blocks and at the top level
A block inherits __method__ from the method that defines it.
def ship_order(items)
items.each { __method__ }
end
ship_order([1, 2, 3])
# => [:ship_order, :ship_order, :ship_order]
To get the name of the surrounding Proc or lambda itself, use Proc#name (Ruby 3.0+). At the top level there is no enclosing method, so __method__ returns nil. Code that interpolates the result into a log line should be ready for that, e.g. with to_s.
Two related traps:
- Inside a block passed to
define_method,__method__returns the block’s own name, not the method being defined. Usecaller_locations(1, 1).labelto recover the dynamic name. - Inside
method_missing,__method__is always:method_missing. The missing name arrives as thenameargument.
class Validator
[:name, :email, :age].each do |attr|
define_method("validate_#{attr}") do
# __method__ here is the block's own name, not the dynamic one
name = caller_locations(1, 1).label
"validating via #{name} for #{attr}"
end
end
end
Validator.new.validate_email
# => "validating via validate_email for email"
The caller_locations(1, 1).label call reaches one frame up the stack to grab the method that is actually running.
Common pitfalls
- Alias leakage. Dispatching on
__method__ignores the alias name. Use__callee__or pass the name explicitly. define_methodtrap.__method__inside the block is not the defined method’s name.- Top-level returns
nilrather than:mainor any other symbol. - Stored procs and lambdas lose a meaningful
__method__once they leave their defining scope; useProc#nameor the binding.
See also
Kernel#send- call methods by name, a natural pairing with introspection.Object#respond_to?- check whether a method exists before sending.BasicObject#method_missing- the dynamic-methods companion to__method__.