2015-06-23 7 views
2

Когда я определяю метод внутри блока instance_eval для класса, он создает метод класса, который является точным.define_method in instance_eval

Eg)

class A 
end 

A.instance_eval do 
    def method; end 
end 

A.method #works 

Но когда я использую define_method внутри instance_eval создает метод экземпляра вместо метода класса Eg)

A.instance_eval do 
    define_method(:method1) {} 
end 
A.method1 # NoMethodError: undefined method `method1' 
A.new.method1 # Works fine 

Я не могу понять выше явлений. Пожалуйста, помогите мне.

+0

Если вы хотите, чтобы ваша боль болела, найдите концепцию «default definee» (то есть «вещь, где' def' заканчивается методом put »), а какой из методов' * _eval' изменяется сам ', который изменяет значение по умолчанию, которое меняет и то, и какой из методов' define _ * _ method 'соблюдает дефолт по умолчанию, а какие нет. Это довольно беспорядок. –

+0

http://yugui.jp/articles/846 –

ответ

2

Это причудливое поведение имеет смысл, если вы посмотрите на instance_eval в контексте экземпляров (что является его основной целью).

class A 
end 

a = A.new 
a.instance_eval do 
    def foo 
    end 
end 

Где находится foo? Единственное разумное место, где я могу думать «синглтон класс с, а на самом деле это правда

a.method(:foo).owner == a.singleton_class 
# true 

Так что это демонстрирует правило

def внутри instance_eval определяет метод в self» a одноплодной класса s ,

, который полностью соответствует тому, что вы видели.

A.instance_eval do 
    # defines method in A's singleton class! 
    def method; end 
end 

Так почему же define_method ведут себя по-другому? Потому что в отличие от def это метод ! Так что это

A.instance_eval do 
    define_method(:foo) {} 
end 

действительно просто

A.define_method(:foo) {} 

который является метапрограммированием способ создания нормальных методов экземпляра. Эта несогласованность может показаться раздражающей, но снова взгляните на случай для нормальных случаев, и вы поймете, почему def и define_methodне могут быть последовательными. Это

a.instance_eval do 
    define_method(:foo) {} 
end 

действительно просто

a.define_method(:foo) {} 

который нонсенс

NoMethodError: undefined method `define_method' for #<A:0x00008> 
-1

Для:

class A; end 

A.instance_eval do 
    puts "self=#{self}" 
    def m; puts "hi"; end 
    define_method(:n) {puts "ho" } 
end 
    #=> "self=A" 

мы находим, что:

A.methods(false)   #=> [:m] 
A.instance_methods(false) #=> [:n] 
A.m      # hi 
A.n      # NoMethodError:... 
A.new.m     # NoMethodError:... 
A.new.n     # ho 

A.instance_eval открывает класс A, а метод m определен на A.Затем вызывается метод define_method, который создает метод экземпляра :n на его приемнике, A.

Предположим, что мы должны были использовать Module#class_eval, а не BasicObject#instance_eval:

A.class_eval do 
    puts "self=#{self}" 
    def m; puts "hi"; end 
    define_method(:n) {puts "ho" } 
end 
    #=> "self=A" 

мы находим, что:

A.methods(false)   #=> [] 
A.instance_methods(false) #=> [:m, :n] 
A.m      # NoMethodError:... 
A.n      # NoMethodError:... 
A.new.m     # hi 
A.new.n     # ho 

так что вы видите, что это поведение такое же, как:

class A 
    puts "self=#{self}" 
    def m; puts "hi"; end 
    define_method(:n) {puts "ho" } 
end 

и здесь методы экземпляра могут быть определены либо def o r define_method.