定义在Ruby中使用范围外变量的方法

时间:2011-05-09 15:17:49

标签: ruby metaprogramming closures

我想创建一个Test :: Unit test_helper方法,我可以在测试执行后调用它来擦除一堆表。这是我的一般想法:

def self.wipe_models(*models)
  def teardown
    models.each do |model|
      model = model.to_s.camelize.constantize
      model.connection.execute "delete from #{model.table_name}"
    end
  end
end

然而,当teardown运行时,我得到:

  

未定义的局部变量或方法`models'

对我来说,看起来“def”区块不遵守关闭的通常规则;我无法访问在其范围之外定义的变量。

那么,如何访问在“def”方法声明之外定义的变量?

3 个答案:

答案 0 :(得分:4)

方法定义不是Ruby中的闭包。 classmoduledefend关键字都是范围门。为了保持范围门的范围,你必须通过一个块;块是闭包,因此在它们被定义的范围内运行。

def foo
  # since we're in a different scope than the one the block is defined in,
  # setting x here will not affect the result of the yield
  x = 900
  puts yield  #=> outputs "16"
end

# x and the block passed to Proc.new have the same scope
x = 4
square_x = Proc.new { x * x }


foo(&square_x)

答案 1 :(得分:4)

您可以使用define_method

作为闭包
def self.wipe_models(*models)
  define_method(:teardown) do
    models.each do |model|
      model = model.to_s.camelize.constantize
      model.connection.execute "delete from #{model.table_name}"
    end
  end
end

现在方法体是一个块,可以访问models

答案 2 :(得分:1)

使用类实例变量:

cattr_accessor :models_to_wipe

def self.wipe_models(*models)
  self.models_to_wipe = models
end

def teardown
  self.class.models_to_wipe.each do |model|
    model = model.to_s.camelize.constantize
    model.connection.execute "delete from #{model.table_name}"
  end
end