你可以在Ruby中调用者的上下文中评估代码吗?

Sam*_*ron 23 ruby

基本上我想知道是否可以在Ruby中完成以下操作.

例如:

def bar(symbol) 
  # magic code goes here, it outputs "a = 100" 
end

def foo
  a = 100 
  bar(:a) 
end
Run Code Online (Sandbox Code Playgroud)

gle*_*man 17

你必须将foo上下文传递给bar:

def foo
  a = 100
  bar(:a, binding)
end
def bar(sym, b)
  puts "#{sym} is #{eval(sym.to_s, b)}"
end
Run Code Online (Sandbox Code Playgroud)


Sam*_*ron 15

没有内置的方式来获得主叫绑定在1.8.x的或1.9.x中使用Ruby

您可以使用https://github.com/banister/binding_of_caller来解决.

在MRI 2.0中,您可以使用RubyVM :: DebugInspector,请参阅:https://github.com/banister/binding_of_caller/blob/master/lib/binding_of_caller/mri2.rb

MRI 2.0中的工作样本:

require 'debug_inspector'

def bar(symbol)
  RubyVM::DebugInspector.open do |inspector|
    val = eval(symbol.to_s, inspector.frame_binding(2))
    puts "#{symbol}: #{val}"
  end
end

def foo
  a = 100
  bar(:a)
end

foo
# a: 100
Run Code Online (Sandbox Code Playgroud)

  • 应该包括免责声明:请不要这样做,除非你*实际*用它进行某种调试. (2认同)

Jai*_*ham 8

这是一个更简单的语法黑客,使用传入的块绑定:

  def loginfo &block
    what = yield.to_s
    evaled = eval(what, block.binding)
    Rails.logger.info "#{what} = #{evaled.inspect}"
  end
Run Code Online (Sandbox Code Playgroud)

像这样叫:

  x = 1
  loginfo{ :x }
Run Code Online (Sandbox Code Playgroud)

将退出:

  x = 1
Run Code Online (Sandbox Code Playgroud)


Tai*_*ada 6

仅供参考,这是一种"hacky方式".这是我对着名的ppp.rb的(重新)实现:

#!/usr/bin/ruby
#
# better ppp.rb
#

require 'continuation' if RUBY_VERSION >= '1.9.0'

def ppp(*sym)
  cc = nil
  ok = false

  set_trace_func lambda {|event, file, lineno, id, binding, klass|
    if ok
      set_trace_func nil
      cc.call(binding)
    else
      ok = event == "return"
    end
  }
  return unless bb = callcc{|c| cc = c; nil }

  sym.map{|s| v = eval(s.to_s, bb); puts "#{s.inspect} = #{v}"; v }
end

a = 1
s = "hello"
ppp :a, :s

exit 0
Run Code Online (Sandbox Code Playgroud)

这目前在1.9中失败.[012] 由于ruby的set_trace_func中的错误.