Just like JavaScript, in ruby, lambda can be passed over functions.
In JavaScript this
will be resolved as the caller object.
But what about ruby? Does the same mechanism applied to ruby's lambda or block too? How? Can you give me some example code?
By the way I've read the The Ruby Programming Language, but I couldn't find any helpful info from it..
In Ruby, self
is lexically scoped, i.e. self
inside a block or lambda is whatever it would be at that same place without being in a block or lambda.
class << foo = Object.new
def bar
puts "`self` inside `foo#bar` is #{self.inspect}"
yield self
end
end
this = self
foo.bar do |that|
puts "`self` inside the block is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the block."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the block is main
# … which is the same as outside the block.
This also applies to lambdas:
class << foo = Object.new
def bar(lambda)
# ↑↑↑↑↑↑↑↑
puts "`self` inside `foo#bar` is #{self.inspect}"
lambda.(self)
#↑↑↑↑↑↑↑↑↑↑↑↑
end
end
this = self
foo.bar(-> that do
# ↑↑↑↑↑↑↑↑
puts "`self` inside the lambda is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the lambda."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end)
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the lambda is main
# … which is the same as outside the lambda.
There are, however, a fixed number of very specific reflective methods that do change self
, those are the methods in the *_{exec|eval}
family:
BasicObject#instance_exec
Module#module_exec
BasicObject#instance_eval
Module#module_eval
Class#module_eval
Example (changing only one relevant line from above):
class << foo = Object.new
def bar(&blk)
# ↑↑↑↑↑↑
puts "`self` inside `foo#bar` is #{self.inspect}"
instance_exec(self, &blk)
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
end
end
this = self
foo.bar do |that|
puts "`self` inside the block is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the block."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the block is #<Object:0xdeadbeef48151623>
# … which is the same as inside the method.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
This also applies to lambdas (converted to blocks):
foo.bar(&-> that do
# ↑↑↑↑↑↑↑↑
puts "`self` inside the lambda is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the lambda."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end)
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the lambda is #<Object:0xdeadbeef48151623>
# … which is the same as inside the method.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Lastly, Ruby allows you to reflectively reify the lexical environment at a specific call-site into a Binding
object. You can then, in turn, evaluate code in the context of this specific binding using either the binding's Binding#eval
method or by passing the binding object to Kernel#eval
:
class << foo = Object.new
def bar(str)
puts "`self` inside `foo#bar` is #{self.inspect}"
binding.eval(str)
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
end
end
$this = self
foo.bar <<~'HERE'
puts "`self` inside the eval'd string is #{self.inspect}"
if $this.equal?(self)
puts "… which is the same as outside the eval'd string."
end
HERE
# `self` inside `foo#bar` is #<Object:0x0070070070070070>
# `self` inside the eval'd string is #<Object:0x0070070070070070>
self
is one of three implicit contexts in Ruby:
self
There is a nice blog article by yugui, which mostly talks about the default definee but also touches briefly on self
: Three implicit contexts in Ruby. There is also an older article in Japanese which goes into a little more detail: Rubyの呼び出し可能オブジェクトの比較 (3) - なんかklassの話.