Я бы использовал метод Kernel#set_trace_func
, чтобы объяснить вам, что происходит под капотом. Посмотрите сначала ниже код и выход:
trace = lambda do |event,file,line,id,binding,klass|
p [event,File.basename(file),line,id,binding,klass]
end
set_trace_func trace
class MyClass
def self.bar;end
def one
def two
end
end
end
obj = MyClass.new
obj.one
obj.instance_eval do
def three
end
end
выход:
-----------------
----------------
-----------------
-----------------
-----------------
----------------- # part A
["c-call", "test.rb", 9, :singleton_method_added, #<Binding:0x83ab2b0>, BasicObject]
["c-return", "test.rb", 9, :singleton_method_added, #<Binding:0x83aaeb4>, BasicObject]
["line", "test.rb", 10, nil, #<Binding:0x83aab80>, nil]
["c-call", "test.rb", 10, :method_added, #<Binding:0x83aa900>, Module]
["c-return", "test.rb", 10, :method_added, #<Binding:0x83aa07c>, Module]
----------------------------- # part B
["line", "test.rb", 16, nil, #<Binding:0x83a976c>, nil]
["c-call", "test.rb", 16, :new, #<Binding:0x83a9488>, Class]
["c-call", "test.rb", 16, :initialize, #<Binding:0x83a90a0>, BasicObject]
["c-return", "test.rb", 16, :initialize, #<Binding:0x83a8e20>, BasicObject]
["c-return", "test.rb", 16, :new, #<Binding:0x83a8b28>, Class]
---------------------------
---------------------------
--------------------------- # part C
["c-call", "test.rb", 11, :method_added, #<Binding:0x83a7de0>, Module]
["c-return", "test.rb", 11, :method_added, #<Binding:0x83a79f8>, Module]
--------------------------- # part D
["line", "test.rb", 18, nil, #<Binding:0x83a7034>, nil]
["c-call", "test.rb", 18, :instance_eval, #<Binding:0x83a6c10>, BasicObject]
["line", "test.rb", 19, nil, #<Binding:0x83a65f8>, nil]
["c-call", "test.rb", 19, :singleton_method_added, #<Binding:0x83a61d4>, BasicObject]
["c-return", "test.rb", 19, :singleton_method_added, #<Binding:0x83a5ef0>, BasicObject]
["c-return", "test.rb", 18, :instance_eval, #<Binding:0x83a5d4c>, BasicObject]
Пояснение:
Посмотрите на линий ниже части А. Это просто говорит нам, когда Ruby найдет ключевое слово def
внутри класса, оно добавит этот метод как метод экземпляра в этот класс. Это делается путем вызова метода hook Module#method_added
. То же объяснение относится к двум строкам ниже часть C.
Теперь что происходит внутри obj.instance_eval {..}
?
Хорошо, это будет очищен, если вы посмотрите на линии ниже части D. Посмотрите от последнего, первого и второго line.Inside instance_eval
блока, def third
, вызывает third
быть добавлен в качестве singleton_method
объекта ob
, с помощью вызова метода крюка BasicObject#singleton_method_added
.
Это как MRI было написано.
* + 1 * для очень хорошего исследования ... :) –
thnks, когда я чувствую, что у меня есть дело с вещами, причуды, подобные этим, приходят и кусают меня :), сказав это, если вы определите методы в верхнем слое, эти методы становятся частными методами экземпляра Object, а не singleton-методами main (и я где-то читал, что это преднамеренный и только специальный случай) – orange
ha, 'def self.two; end' будет вести себя как instance_eval – fl00r