2010-05-14 83 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 

这样,无码逃避是必要的。