2010-05-14 80 views
0

我有以下程序。ruby​​混淆 - 局部變量或instance_method?

module C 
    def self.included(base) 
    base.extend(ClassMethods) 

    end 

    module ClassMethods 
    def test_for 
     class_eval <<-DEFINECLASSMETHODS 
     def self.my_method(param_a) 
      puts "SELF is: #{self.inspect}" 
      puts param_a 
      puts "#{param_a}" 
     end 
     DEFINECLASSMETHODS 
    end 
    end 
end 

class A 
    include C 
end 

class B < A 
    test_for 
end 
當我運行 B.new.my_method("aaa")

,我得到這個錯誤

NameError: undefined local variable or method `param_a' for B:Class 

我感到很困惑。

我定義param_a如在類方法my_method一個局部變量,

puts param_a 

運行良好,並且將輸出 「AAA」。

然而,

puts "#{param_a}" 

輸出該錯誤。

爲什麼?

任何人都可以解釋這一點嗎?

回答

1

這些都是一些majorly複雜箍您通過,跳躍實現基本上是這樣的:

module C 
    def test_for 
    define_singleton_method :my_method do |param_a| 
     puts "SELF is: #{inspect}" 
     p param_a 
    end 
    end 
end 

class A 
    extend C 
end 

class B < A 
    test_for 
end 

B.my_method 'foo' 
# => SELF is: B 
# => "foo" 

編輯:我只是意識到上面的解決方案是仍然比它需要更爲複雜的是。事實上,我們並不需要任何的元編程在所有

module C 
    module D 
    def my_method(param_a) 
     puts "SELF is: #{inspect}" 
     p param_a 
    end 
    end 
    def test_for 
    extend D 
    end 
end 

class A 
    extend C 
end 

class B < A 
    test_for 
end 

B.my_method 'foo' 
# => SELF is: B 
# => "foo" 
3

因爲#{}不進行內插param_a到傳遞給放字符串你得到這個錯誤 - 它插入傳遞給class_eval的字符串。當你逃避它,它會工作,即

puts "\#{param_a}" 

您也可以禁用定界符內插值使用<<-'DEFINECLASSMETHODS'代替<<-DEFINECLASSMETHODS。這也將允許您使用其他元字符而不必轉義它們。

+0

該死!我完全錯過了!鷹眼+1!就我個人而言,我規定我總是使用單引號字符串,除非我100%肯定我絕對肯定*想要*字符串插值發生。這只是一個例子,爲什麼這是一個好主意。 – 2010-05-14 11:42:24

+1

這是我總是推薦使用'class_eval'的塊形式的衆多原因之一。 – Chuck 2010-05-14 16:40:28

2

嘗試使用 「class_eval做;末」,而不是像這樣:

def test_for 
    class_eval do 
    def self.my_method(param_a) 
     puts "SELF is: #{self.inspect}" 
     puts param_a 
     puts "#{param_a}" 
    end 
    end 
end 

這樣,無碼逃避是必要的。