ruby令人困惑 - 局部变量或instance_method?

时间:2010-05-14 09:03:43

标签: ruby metaprogramming

我有以下程序。

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

我很困惑。

我在类方法my_method,

中将param_a定义为局部变量
puts param_a

运行良好,并输出“aaa”。

然而,

puts "#{param_a}"

输出该错误。

为什么?

任何人都能解释一下吗?

3 个答案:

答案 0 :(得分:3)

你得到那个错误,因为#{}没有将param_a插入到传递给puts的字符串中 - 它将它插入传递给class_eval的字符串中。它会逃脱它,即

puts "\#{param_a}"

您还可以使用<<-'DEFINECLASSMETHODS'代替<<-DEFINECLASSMETHODS在heredoc中禁用插值。这也允许您使用其他元字符而不必转义它们。

答案 1 :(得分:2)

请尝试使用“class_eval do; end”,如下所示:

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 

这样,不需要代码转义。

答案 2 :(得分:1)

这些是你正在跳过的一些非常复杂的箍,基本上实现了这个:

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"