Можете ли вы оценить код в контексте вызывающего в Ruby? - PullRequest
23 голосов
/ 31 августа 2009

По сути, мне интересно, можно ли сделать следующее в Ruby

Так, например:

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

def foo
  a = 100 
  bar(:a) 
end

Ответы [ 5 ]

17 голосов
/ 31 августа 2009

Вы должны передать контекст foo в bar:

def foo
  a = 100
  bar(:a, binding)
end
def bar(sym, b)
  puts "#{sym} is #{eval(sym.to_s, b)}"
end
15 голосов
/ 06 сентября 2009

Существует встроенного способа получить привязку вызывающих в Ruby в 1.8.X или 1.9.X.

Вы можете использовать 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

Рабочий образец в МРТ 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
8 голосов
/ 10 мая 2013

Вот более легкий синтаксический взлом, использующий переданную блокировку блока:

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

называется так:

  x = 1
  loginfo{ :x }

выйдет из системы:

  x = 1
6 голосов
/ 24 мая 2011

Просто к вашему сведению, вот "хакерский путь". Это моя (пере) реализация хорошо известного 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

В настоящее время это не с 1.9. [012] из-за ошибки в set_trace_func в ruby.

3 голосов
/ 31 августа 2009

Проверьте статью Переменные в рубине

class Reference
  def initialize(var_name, vars)
    @getter = eval "lambda { #{var_name} }", vars
    @setter = eval "lambda { |v| #{var_name} = v }", vars
  end
  def value
    @getter.call
  end
  def value=(new_value)
    @setter.call(new_value)
  end
end

def ref(&block)
  Reference.new(block.call, block.binding)
end

def bar(ref)
  # magic code goes here, it outputs "a = 100" 
  p ref.value
end

def foo
  a = 100 
  bar(ref{:a}) 
end

foo
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...