我怎样才能从method_missing的绑定? [英] How can I get the binding from method_missing?

查看:134
本文介绍了我怎样才能从method_missing的绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找到一种方式来获得的method_missing内红宝石调用者(1.8)的结合,但我似乎无法找到一个方法来做到这一点。

I am trying to find a way to get the binding from the caller within method_missing in Ruby (1.8), but I can't seem to find a way to do it.

幸运地是,code解释我想做些什么:

Hopefully the following code explains what I would like to do:

class A
  def some_method
    x = 123
    nonexistent_method
  end

  def method_missing(method, *args, &block)
    b = caller_binding # <---- Is this possible?
    eval "puts x", b
  end
end

A.new.some_method
# expected output:
#   123

所以...有没有办法来获得主叫方的结合,或者在Ruby中这只是不可能的(1.8)?

So... is there a way to obtain the caller's binding, or is this just impossible in Ruby (1.8)?

推荐答案

下面是一个(有些脆弱)黑客:

Here's a (somewhat fragile) hack:

# caller_binding.rb
TRACE_STACK = []
VERSION_OFFSET = { "1.8.6" => -3, "1.9.1" => -2 }[RUBY_VERSION]
def caller_binding(skip=1)
  TRACE_STACK[ VERSION_OFFSET - skip ][:binding]
end
set_trace_func(lambda do |event, file, line, id, binding, classname|
  item = {:event=>event,:file=>file,:line=>line,:id=>id,:binding=>binding,:classname=>classname}
  #p item
  case(event)
  when 'line'
    TRACE_STACK.push(item) if TRACE_STACK.empty?
  when /\b(?:(?:c-)?call|class)\b/
    TRACE_STACK.push(item)
  when /\b(?:(?:c-)?return|end|raise)\b/
    TRACE_STACK.pop
  end
end)

这与您的例子,但我还没有与其他许多测试它

This works with your example, but I haven't tested it with much else

require 'caller_binding'
class A
  def some_method
    x = 123
    nonexistent_method
  end
  def method_missing( method, *args, &block )
    b = caller_binding
    eval "puts x", b
  end
end

x = 456
A.new.some_method #=> prints 123
A.new.nonexistent_method #=> prints 456

当然,这是不行的,如果绑定不定义你要评估的变量,但这是绑定的一个普遍问题。如果没有定义的变量,它不知道它是什么。

Of course, this won't work if the binding doesn't define the variable you're trying to evaluate, but this is a general issue with bindings. If a variable is not defined, it doesn't know what it is.

require 'caller_binding'
def show_x(b)
  begin
    eval <<-SCRIPT, b
      puts "x = \#{x}"
    SCRIPT
  rescue => e
    puts e
  end
end

def y
  show_x(caller_binding)
end

def ex1
  y #=> prints "undefined local variable or method `x' for main:Object"
  show_x(binding) #=> prints "undefined local variable or method `x' for main:Object"
end

def ex2
  x = 123
  y #+> prints "x = 123"
  show_x(binding) #+> prints "x = 123"
end

ex1
ex2

要解决这个问题,你需要做一些错误的评估字符串中操作:

To get around this, you need to do some error handling within the evaluated string:

require 'caller_binding'
def show_x(b)
  begin
    eval <<-SCRIPT, b
      if defined? x
        puts "x = \#{x}"
      else
        puts "x not defined"
      end
    SCRIPT
  rescue => e
    puts e
  end
end

def y
  show_x(caller_binding)
end

def ex1
  y #=> prints "x not defined"
  show_x(binding) #=> prints "x not defined"
end

def ex2
  x = 123
  y #+> prints "x = 123"
  show_x(binding) #+> prints "x = 123"
end

ex1
ex2

这篇关于我怎样才能从method_missing的绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆