def singleton_class
class << self
self
end
end
class Human
proc = lambda { puts 'proc says my class is ' + self.name.to_s }
singleton_class.instance_eval do
define_method(:lab) do
proc.call
end
end
end
class Developer < Human
end
Human.lab # class is Human
Developer.lab # class is Human ; oops
Following solution works.
def singleton_class
class << self
self
end
end
class Human
proc = lambda { puts 'proc says my class is ' + self.name.to_s }
singleton_class.instance_eval do
define_method(:lab) do
self.instance_eval &proc
end
end
end
class Developer < Human
end
Human.lab # class is Human
Developer.lab # class is Human ; oops
Why Developer.lab is reporting that it is Human ? And what can be done so that proc reports Developer when Developer.lab is invoked.
The closure is capturing self in the context where it is defined - just like closures should do. So, when it is called, it will use the references to the context it captured. A closure is not the ideal tool to define the intended functionality. Instead of proc.call, the content of the "define_method" invocation should be "puts 'proc says my class is ' + name.to_s"
It's subtle, but it boils down to simply calling the block (in which case it acts as a normal closure, and self
corresponds to where it was defined, ie in Human
), or using it (directly) as a block for a method definition or instance_eval
:
def singleton_class
class << self
self
end
end
class Human
PROC = proc { puts 'proc says my class is ' + self.name.to_s }
singleton_class.instance_eval do
define_method(:lab) do
PROC.call
end
define_method(:lab2, &PROC.method(:call))
define_method(:lab3) do
instance_eval(&PROC)
end
define_method(:lab4, &PROC)
end
end
class Developer < Human
end
Human::PROC.call # => "class is Human" (original closure)
Developer.lab # Same as previous line, so "class is Human" (original closure)
Developer.lab2 # ditto
Developer.instance_eval(&Human::PROC) # => "class is Developer" (instance_eval changes sets a different scope)
Developer.lab3 # Same as previous line, so "class is Developer"
Developer.lab4 # ditto
I have to think a little bit about exactly why this works, but for the moment it does work:
class Human
proc = -> { name }
define_singleton_method(:lab, &proc)
end
class Developer < Human; end
require 'test/unit'
class TestClosures < Test::Unit::TestCase
def test_that_the_human_class_is_named_human
assert_equal 'Human', Human.lab
end
def test_that_the_developer_class_is_named_developer
assert_equal 'Developer', Developer.lab
end
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.