从给定的instance_exec块返回

时间:2009-11-10 22:06:39

标签: ruby-on-rails ruby return

我需要使用instance_exec(通过Rails 2.3.2)允许在类的范围内定义和调用块。但是,其中一些块需要在某些情况下尽早返回,这导致我遇到问题。

我的应用程序是使用ruby 1.8.6构建的,但我还需要在1.8.7上运行它。似乎在两个版本之间删除了从lambda中返回的能力。以下内容适用于1.8.6,但在1.8.7中抛出LocalJumpError(意外返回):

class Foo
  def square(n)
    n ** 2
  end

  def cube(n)
    n ** 3
  end

  def call_block(*args, &block)
    instance_exec *args, &block
  end
end

block = lambda { |n|
  return square(n) if n < 5
  cube(n)
}

f = Foo.new
f.call_block(5, &block) # returns 125
f.call_block(3, &block) # returns 9 in 1.8.6, throws a LocalJumpError in 1.8.7

如果我使用return替换了我的块中的next,我确定我可以在1.8.7中使用它,但是next square(n) if n < 5在1.8.6中导致nil

我有什么方法可以在1.8.6和1.8.7中使用它吗?我知道我可以重构我的块以使用分支而不是早期返回,但是一些块更复杂并且有多种情况需要提前返回。

另外,如果我想让我的代码在ruby 1.9中运行,这是否会进一步改变?

编辑:我发现它在1.8.6而不是1.8.7中工作的原因是1.8.7在C源中定义了自己的instance_exec,而1.8 .6使用Rails的实现。如果我使用Rails版本覆盖1.8.7中的instance_exec,它也可以在那里工作。

1 个答案:

答案 0 :(得分:1)

在评论后修改 有关详细信息,请参阅此post

class Foo

  def square(n)
    n ** 2
  end

  def cube(n)
    n ** 3
  end

  def call_block(*args, &block)
      instance_exec *args, &block
    end
end




def a
  block = lambda { | n|
    return square(n) if n < 5
    cube(n)
  }
 f = Foo.new 
puts f.call_block(3, &block) # returns 125
puts "Never makes it here in 1.8.7"
puts f.call_block(5, &block) # returns 9 in 1.8.6, returns nothing in 1.8.7
end

a

此代码不会产生任何结果,因为它会在puts语句之外返回。

procs和lambdas的工作方式在1.9中有所改变。这有助于解释最新进展。

<强>原始

我重构了你的代码,它在所有3个vm下运行。有趣的是,你的代码确实在1.9下执行而没有例外。

class Foo

  def square(n)
    n ** 2
  end

  def cube(n)
    n ** 3
  end

  def call_block(*args, &block)
    block.call(self, *args)
  end
end

block = lambda { |obj, n|
  return obj.square(n) if n < 5
  obj.cube(n)
}

f = Foo.new
puts f.call_block(5, &block) # returns 125
puts f.call_block(3, &block) # returns 9

post可能具有一定的洞察力。