Как я могу получить источник и значения переменных в рубине tracebacks?

В соответствии с ECMAScript 5 вы можете комбинировать Object.keys() и Array.prototype.forEach() :

var obj = { first: "John", last: "Doe" };

Object.keys(obj).forEach(function(key) {
    console.log(key, obj[key]);
});

ES6 добавляет for...of :

for (const key of Object.keys(obj)) {
    console.log(key, obj[key]);
}

ES2017 добавляет Object.entries() , что позволяет не смотреть на каждое значение в исходном объекте:

Object.entries(obj).forEach(
    ([key, value]) => console.log(key, value)
);

Итерации Object.keys() и Object.entries() повторяются в том же порядке, что и петля for...in , но игнорируют цепочку прототипов . Исправлены только перечислимые свойства объекта.

Изменить: ES2016 → ES6

7
задан Glorfindel 4 January 2019 в 08:40
поделиться

1 ответ

AFAIK, когда-то исключение было поймано, слишком поздно для захвата контекста, в котором это было повышено. При захвате нового вызова исключения Вы могли бы использовать evil.rb's, Связывающий of_caller, чтобы захватить объем вызова и сделать

eval("local_variables.collect { |l| [l, eval(l)] }", Binding.of_caller)

Но это - вполне большой взлом. Правильный ответ должен, вероятно, расширить Ruby для разрешения некоторого контроля стека вызовов. Я не уверен, позволят ли некоторые новые реализации Ruby это, но я действительно помню обратную реакцию против Привязки of_caller, потому что она сделает оптимизацию намного тяжелее.

(Честно говоря, я не понимаю эту обратную реакцию: пока интерпретатор записывает достаточно информации о выполненной оптимизации, Привязка of_caller должна смочь работать, хотя, возможно, медленно.)

Обновление

Хорошо, я понял это. Длинноватый код следует:

class Foo < Exception
  attr_reader :call_binding

  def initialize
    # Find the calling location
    expected_file, expected_line = caller(1).first.split(':')[0,2]
    expected_line = expected_line.to_i
    return_count = 5  # If we see more than 5 returns, stop tracing

    # Start tracing until we see our caller.
    set_trace_func(proc do |event, file, line, id, binding, kls|
      if file == expected_file && line == expected_line
        # Found it: Save the binding and stop tracing
        @call_binding = binding
        set_trace_func(nil)
      end

      if event == :return
        # Seen too many returns, give up. :-(
        set_trace_func(nil) if (return_count -= 1) <= 0
      end
    end)
  end
end

class Hello
  def a
    x = 10
    y = 20
    raise Foo
  end
end
class World
  def b
    Hello.new.a
  end
end

begin World.new.b
rescue Foo => e
  b = e.call_binding
  puts eval("local_variables.collect {|l| [l, eval(l)]}", b).inspect
end
7
ответ дан 7 December 2019 в 07:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: