Могу ли я получить доступ к источнику блока ruby без & блока? - PullRequest
1 голос
/ 23 января 2020

Я использую Pry в Ruby 2.5 для отладки проблемы в базовом классе (Net::HTTP)

Я получаю исключение, вызванное ответом HTTP 404, и я хочу изучить тело запрос, который был сделан. Для этого я хочу проверить блок, который был передан в start, но метод start не имеет параметра, он вызывается с помощью yield:

Frame type: method

From: /usr/share/ruby/net/http.rb @ line 910 Net::HTTP#start:

    905: def start  # :yield: http
    906:   raise IOError, 'HTTP session already opened' if @started
    907:   if block_given?
    908:     begin
    909:       do_start
 => 910:       return yield(self)

Используя Pry есть ли способ просмотреть источник блока, если этот блок не передан в параметре &block?

Пила Печать исходного кода Ruby блока но это не помогает мне, потому что у меня нет параметра метода для использования здесь.

Ответы [ 3 ]

2 голосов
/ 24 января 2020

Итак, реальная проблема в том, что я не прочитал всю справку Pry (в частности, rescue-pry) и не знал о команде up ...

Usage: up [OPTIONS]
  Go up to the caller's context. Accepts optional numeric parameter for how many frames to move up.
  Also accepts a string (regex) instead of numeric; for jumping to nearest parent method frame which matches the regex.
  e.g: up      #=> Move up 1 stack frame.
  e.g: up 3    #=> Move up 2 stack frames.
  e.g: up meth #=> Jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`.

    -h, --help      Show this message.

Выполнив up в сеансе pry из возбужденного исключения, я смог добраться до блока, где возникло исключение, и проверить нужные мне локальные переменные.

2 голосов
/ 24 января 2020

Используя Pry, есть ли способ просмотреть источник блока, если этот блок не передан в параметре & block?

Ваша проблема двоякая: вам нужно 1) получить неявный блок и 2) напечатать его источник.

Для 1) вы можете просто вызвать Proc.new в контексте метода, чтобы получить аргумент блока как pro c.

Таким образом, вместо:

def foo(&block)
  # ...
end

Вы также можете получить блок с помощью:

def foo
  block = Proc.new
  # ...
end

Для 2) вы можете использовать камень sourcify :

require 'sourcify'

prc = Proc.new { |i| i * 2 }
prc.to_source
#=> "proc { |i| (i * 2) }"

Применительно к вашей проблеме:

# foo.rb
require 'pry'
require 'sourcify'

def foo
  binding.pry
end

foo { |i| i * 2 }
$ ruby foo.rb

From: foo.rb @ line 6 Object#foo:

    4: def foo
 => 5:   binding.pry
    6: end

[1] pry(main)> block = Proc.new
#=> #<Proc:0x00007f9373b1c368@foo.rb:9>

[2] pry(main)> block.call(123)
#=> 246

[3] pry(main)> block.to_source
#=> "proc { |i| (i * 2) }"
1 голос
/ 24 января 2020

TL; DR Вы можете попробовать использовать Kernel # caller .


Давайте рассмотрим файл с именем foo.rb:

(в этом примере используется byebug, но поток с binging.pry почти такой же)

1: require 'byebug'
2: 
3: def bar
4:   byebug
5: 
6:   yield
7: end
8: 
9: bar { 'some string' }

Когда мы запустим этот файл с ruby foo.rb, мы остановимся на операторе byebug .

[1, 9] in foo.rb
   1: require 'byebug'
   2: 
   3: def bar
   4:   byebug
   5: 
=> 6:   yield
   7: end
   8: 
   9: bar { 'some string' }

Затем мы можем выполнить caller, и будет напечатано что-то вроде следующего:

(выходные данные намеренно уменьшены и отформатированы)

(byebug) caller
[
  "~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/processors/command_processor.rb:97:in `process_commands'",
  "~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/processors/command_processor.rb:55:in `at_line'",
  "~/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/byebug-11.0.1/lib/byebug/context.rb:98:in `at_line'",
  "foo.rb:6:in `bar'",
  "foo.rb:9:in `<main>'"
]

As Вы можете видеть, caller возвращает текущий стек выполнения в виде массива, содержащего строки в форме file:line в `method '.

Последняя строка в этом массиве указывает, где был вызван bar.

Зная эту информацию, вы можете открыть файл с помощью этого bar вызова и отследить, какой блок был передан в него.

(foo.rb:9 в данном конкретном случае)

Надеюсь, что помогает.

В качестве бонуса, есть замечательная статья Tenderlove - Я отладчик пута , wh Прежде чем вы найдете решение, вероятно, для каждой Ruby проблемы отладки.

...