Я люблю REPL. Это отличный инструмент для разработки. В любом приличном языке есть REPL. В Лиспе это есть. Python есть. Как и Haskell. И у Ruby, очевидно, он есть!

REPL означает R ead E val P rint L oop. Это интерфейс командной строки для взаимодействия с языком программирования. В большинстве интерактивных языков программирования есть REPL. (Я не проверял.) Эта номенклатура является производной от реализации Лиспа, которая в своей основной форме может быть однострочным:

(loop (print (eval (read))))

Lisp REPL очень мощные. Мы можем проверить дерево стека, (повторно) выполнить кадр (обычно вызов функции), изменить аргументы кадра и повторно выполнить его, изменить определение функции и повторно выполнить вызывающий его кадр.

С такими высокими ожиданиями неудивительно, что IRB (REPL Ruby по умолчанию) не выглядит таким мощным. (Думаю, вы со мной согласитесь.) Pry - довольно мощная альтернатива IRB и содержит много новых функций. Но все же ... его нельзя сравнивать с Лиспом. Тем не менее, есть несколько функций, которые (я думаю) понравятся новичкам. Я намерен пройтись по ним в этом посте.

Предыдущее оценочное значение

При изучении Ruby мне постоянно приходилось использовать значение предыдущей оценки. Допустим, я рассчитал налоговую стоимость продукта и теперь хочу узнать окончательную цену:

pry(main)> price, tax_rate = 34, 0.08
=> [34, 0.08]
pry(main)> price * tax_rate
=> 2.72
pry(main)> final_price = price + # damn! -_-

Мне потребовалось время, чтобы понять, что мы можем получить доступ к предыдущему значению с помощью _ (подчеркивание). С двумя символами подчеркивания __ мы получаем доступ ко второму с последнего значения.

pry(main)> price, tax_rate = 34, 0.08
=> [34, 0.08]
pry(main)> price * tax_rate
=> 2.72
pry(main)> final_price = price + _
=> 36.72
pry(main)> __
=> 2.72

Где я?

Одна из методологий отладки - это установка точек останова в наш код. В Pry мы делаем это с помощью выражения binding.pry. Это приводит к остановке выполнения на этой строке. Когда это произойдет, на консоли Ruby отобразится что-то вроде этого:

pry(main)> Grid.generate(6, 6)
From: /Users/bjacquet/Projects/gol/gol.rb @ line 27 Grid.generate:
    25: def self.generate(width, height)
    26:   self.new(Array.new(height).collect do
 => 27:   binding.pry
    28:   Array.new(width).collect { rand(2) }
    29: end
[1] pry(Grid)> 

Он показывает строку кода, в которой остановлено выполнение, обозначенную =>. (Это 27-я строка.) Также некоторый контекст кода с окружающими строками. Мы также можем сделать вывод, что он остановился внутри метода Grid.generate и определен в файле gol.rb.

Эта информация также доступна в любое время, набрав команду whereami.

Если бы размер этого метода был вдвое больше, мы все равно могли бы видеть его полное содержимое, используя команду show-source как таковую:

pry(main)> show-source Grid.generate
From: gol.rb @ line 25:
Owner: #<Class:Grid>
Visibility: public
Number of lines: 7
def self.generate(width, height)
 self.new(Array.new(height).collect do
            binding.pry
            Array.new(width).collect { rand(2) }
          end
         )
end
pry(Grid)>

Воспроизведение истории

Команда Прая hist - это действительно что-то. Помимо прочего, он позволяет просматривать, искать и воспроизводить историю. При вызове без параметров он отображает всю историю Pry, то есть все введенные данные.

pry(main)> hist
1: price, tax_rate = 34, 0.08
2: price * tax_rate
3: price, tax_rate = 34, 0.08
4: price * tax_rate
5: final_price = price + _
6: __
7: Grid.generate(6, 6)
8: show-command Grid.generate
pry(main)>

С опцией --replay мы можем переоценить выражение (я):

pry(main)> hist --replay 3..4
=> [34, 0.08]
=> 2.72

Я считаю, что использовать эту команду быстрее, чем вращать предыдущие входные данные с помощью стрелки вверх.

Позвольте мне исправить это прямо сейчас

Довольно часто мы вводим многострочные выражения в Pry. Чаще, чем хотелось бы, мы печатаем строку с ошибкой. Чтобы исправить это, мы используем команду amend-line. В качестве аргументов он принимает номер строки и код замены.

pry(main)> def hello
pry(main)* puts “hello #{name}”
pry(main)* amend-line 1 def hello(name)
1: def hello(name)
2: puts “hello #{name}”
pry(main)* end
=> :hello

В этом примере я понял, что забыл указать name в качестве аргумента метода. Таким образом, я исправляю это, вызывая команду amend-line в строке 1 с новым кодом. Затем Pry показывает все введенные строки и ждет новых. Я набираю end, и метод определяется.

Идти дальше

Вылет из-за одной ошибки, извините за это! Это стоит того.

Pry также дает нам возможность изменять методы на лету. Для этого нам нужно использовать две команды. Сначала мы меняем метод с помощью команды edit.

pry(main)> edit Grid.generate

Это откроет редактор с курсором на первой строке определения метода. Когда мы закончим, сохраняем изменения и выходим из редактора.

Далее нам нужно оценить новое определение. Команда reload-method делает именно это.

pry(main)> reload-method Grid.generate

Отныне он будет использовать новую версию Grid.generate.

дальнейшее чтение

У Pry есть еще много возможностей, которые стоит открыть. Готовя этот пост, я обнаружил команду amend-line. Он настолько полезен, что мне пришлось его включить. Другие команды, о которых вам следует знать, включают:

  • show-model, перечисляет атрибуты модели и ассоциации классов.
  • show-stack, показывает стек вызовов фреймов. (Чаще всего для отображения чего-либо требуется много времени.)

Pry's wiki хорошо документирована, а также содержит ссылки на другие ресурсы.

Команда Прая help также очень полезна. Я изучил большинство этих функций именно там. (Синдром RTFM)

На этом пока все. Веселитесь и будьте милы! :-)

Я работаю в Runtime Revolution разработчиком на Rails. Мы также работаем с Python, JavaScript… у обоих есть REPL! Мы также помогаем стартапам выйти на новый уровень.