Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby捕获NoMethodError并从发生异常的位置继续执行_Ruby_Metaprogramming - Fatal编程技术网

Ruby捕获NoMethodError并从发生异常的位置继续执行

Ruby捕获NoMethodError并从发生异常的位置继续执行,ruby,metaprogramming,Ruby,Metaprogramming,在Ruby中,我希望捕获在另一个对象中的对象上生成的NoMethodError,然后将一些值返回到引发异常的位置并继续执行。有没有现成的方法可以做到这一点 我想到的最好的办法是: class Exception attr_accessor :continuation end class Outer def hello puts "hello" end class Inner def world puts "world" end de

在Ruby中,我希望捕获在另一个对象中的对象上生成的NoMethodError,然后将一些值返回到引发异常的位置并继续执行。有没有现成的方法可以做到这一点

我想到的最好的办法是:

class Exception
  attr_accessor :continuation
end

class Outer
  def hello
    puts "hello"
  end

  class Inner
    def world
      puts "world"
    end
    def method_missing(method, *args, &block)
      x = callcc do |cc|
        e = RuntimeError.exception(method)
        e.continuation = cc
        raise e
      end
      return x
    end
  end

  def inner(&block)
    inner = Inner.new
    begin
      inner.instance_eval(&block)
    rescue => e
      cc = e.continuation
      cc.call(hello())
    end
    inner
  end
end

o = Outer.new
o.inner do
  hello
  world
end
这张照片

hello
world
有没有更好的方法使用Ruby现有的元编程库来实现这一点?基本上,我不确定callcc是否会继续存在


谢谢。

Ruby有一个名为
throw
的关键字,可以用来向上传播错误。我真的无法从你的帖子中判断出你想把它放在哪个区块,但它是这样的:

class Outer
  catch :NoMethodError do
  #process the exception thrown from inner
  end

  class Inner
    def some_method
      ##...some other processing
      throw :NoMethodError if #....
      #remaining statements
    end
  end
end
在throw语句和catch块执行之后,应该执行
某些方法中的其余语句


希望这有帮助

这个简单的方法怎么样:

class Outer
  def hello
    puts "hello"
  end

  class Inner
    def initialize outer
      @outer = outer
    end

    def world
      puts "world"
    end

    def method_missing(method, *args, &block)
      @outer.send(method, *args, &block)
    rescue NoMethodError # you can also add this
      puts "#{method} is undefined in both inner and outer classes"
    end
  end

  def inner(&block)
    inner = Inner.new self
    inner.instance_eval(&block)
    inner
  end
end

o = Outer.new
o.inner do
  hello
  cruel
  world
end
将打印

hello
cruel is undefined in both inner and outer classes
world
在这种情况下,如果内部类没有定义所需的方法,它将使用将其委托给外部类。您可以捕获
NoMethodError
内部
method\u missing
以控制
Outer
类未定义委托方法时的情况


更新 您也可以使用光纤解决此问题:

class Outer
    def hello
        puts "hello"
    end

    class Inner
        def world
            puts "world"
        end

        def method_missing(method, *args, &block)
            Fiber.yield [method, args, block] # pass method args to outer
        end
    end

    def inner(&block)
        inner = Inner.new
        f = Fiber.new { inner.instance_eval(&block) }
        result = nil # result for first fiber call does not matter, it will be ignored
        while (undef_method = f.resume result) # pass method execution result to inner
            result = self.send(undef_method[0], *undef_method[1], &undef_method[2])
        end
        inner
    end
end

我正在寻找某种机制,在这种机制中,我可以将值返回到发生“抛出”的位置,并继续执行。有没有一种方法可以在内置的东西(比如throw)中实现这一点?我不确定如何返回值,这是可能的,我只是不知道有什么方法。您可以为内部类创建另一个实例变量,并从外部类更新它;这可能是一种方法。@overclock“where”看起来像什么?@Phrogz-在我的问题中,在底部,我打电话给hello and world。在内部进行求值时,对hello的调用将不起作用,因为内部hello不存在。但我想评估一下外面的“你好”。我不希望Inner将Outer子类化,所以我需要从Inner捕获缺少的方法异常,计算Outer#hello,将结果返回到块,然后继续执行Inner#world。只想注意,在这个示例中,我认为您混淆了抛出/缓存在ruby中的工作方式
catch
执行一个“标记”和一个块,如果在执行块的过程中有什么东西抛出,它会向上搜索堆栈,找到带有相应标记的第一个catch,并在catch语句后继续执行。Alex-我喜欢你的第一个简单解决方案,尽管我不确定它是否比异常继续方法更好。不是更糟,只是不同的权衡。例如,现在您的内部必须与外部绑定,因此在进行嵌套时不能使用泛型类而不是内部。但您的解决方案确实避免使用callcc。我希望有人告诉我,如果callcc方法会有问题,因为callcc可能不会(或可能)继续存在。谢谢。@Overclock,正如Matz(Ruby creator)在他的《Ruby编程语言》一书中指出的那样,
因为它们不再得到很好的支持,延续应该被视为一种好奇心,新的Ruby代码不应该使用它们。你是对的,它们的使用是有问题的。如果你真的不想与外部类紧密结合,那么你可以使用我第二个示例中的
Fibers
将控制权移入和移出内部类。我在继续寻找类似的东西。太糟糕了;延续性很好。但你的例子是一个很好的替代品。谢谢