Scope and Binding in Ruby
Understand self, visibility, lexical scope, and bindings.
self and execution context
self is the current receiver; it changes across class, module, and method bodies.
self # top-level => main
class C
self # => C (inside class body)
def who
self # => instance of C
end
end
Method visibility
public (default), protected (callable by instances of same class), private (no explicit receiver).
class Account
def transfer_to(other, amt)
debit(amt)
other.credit(amt) # allowed: protected
end
protected
def credit(amt); @bal += amt end
private
def debit(amt); @bal -= amt end
end
Lexical scope and closures
Blocks/procs capture surrounding locals; methods do not capture outer locals.
prefix = "[x]"
["a","b"].map { |s| "#{prefix} #{s}" }
Binding and eval (use sparingly)
binding captures local scope; eval/instance_eval execute code in a context.
b = binding
x = 1
eval("x + 1", b) # => 2
obj = "str"
obj.instance_eval { self.upcase } # => "STR"
class_eval and define_method
Evaluate code in a class/module context or define methods dynamically.
class Model
end
Model.class_eval do
define_method(:id) { @id ||= 0 }
end
Constant lookup and Module.nesting
Lexical first, then ancestors; use :: for explicit lookup.
module A; X = 1; end
module B; X = 2; end
module A; module C; end; end
A::C.module_eval { Module.nesting } # => [A::C, A]
Summary
selfidentifies the current receiver and changes with context- Visibility controls how methods are invoked
- Closures capture locals;
binding/instance_evalare powerful but use sparingly - Constants resolve lexically first, then via ancestors