REPL
REPL
в мире наколенной разработки расшифровывается как Read → Evaluate → Print Loop. Зачитали, выполнили, напечатали, и так много раз.
Ruby, как и многие другие языки, поставляется с собственной реализацией REPL под названием irb
. Который, хотя и справляется с примитивными задачами, все-таки полностью удовлетворить запросы взыскательного разработчика не может. Но существует и гораздо более развитая альтернатива: pry
.
Вот рекламный отрывок с официального сайта pry
:
Pry — это мощная альтернатива стандартной IRB-оболочке для Ruby. С подсветкой синтаксиса, гибкой архитектурой плагинов, вызовами времени исполнения и просмотром исходников и документации.
И это не просто рекламное бла-бла-бла. Это правда. Я собираюсь показать, как установить и настроить pry
со всеми свистелками и кричалками, чтобы удовлетворить самого искушенного разработчика. Предполагается, что актуальная работающая версия Руби установлена и работает на целевой машине.
Подготовка
Перейдите в консоль и выполните команду:
$ gem install pry pry-theme awesome_print coderay
Все, мы полностью готовы. Давайте запустим pry
… и убедимся, что никакой разницы в сравнении с irb
нет. Внезапно не очень-то приятно.
Ну что ж, давайте научим pry
быть чуточку поумнее.
Конфигурационный файл
Это .pryrc
. В домашнем каталоге уже есть конфигурационный файл, который рассказывает pry
, как выглядеть, и как вести себя в приличном обществе. Если его нет, его можно создать командой cd && touch .pryrc
.
Деликатное наполнение .pryrc
инструкциями
Я собираюсь продемонстрировать различные возможности pry
шаг за шагом. Для нетерпеливых: gist с моим .pryrc
.
-
pry
руководства: здесь собраны килотонны полезной информации для опытных приистов, -
pry
темы оформления: вопросы, ответы, и т. п.
Редактор по умолчанию
Pry.editor = 'vi' # 'code', 'subl'
Настраивает редактор, который будет использоваться для редактирования текущего контекста (команда edit
).
Приглашение командной строки
Pry.config.prompt =
[
->(_obj, _nest_level, _) { "✎ " },
->(*) { " " }
]
.pryrc
— это просто руби-файл, поэтому этот процесс может выполнить любой код, который вы хотите, или даже майнить биткойны, пока вы ждете появления следующего приглашения.
Первый уровень и вложенные уровни (внутри блоков) могут отрисовываться по-разному. Раньше я использовал черный закрашенный треугольник, который вырезает тупой парсер хабра для первого уровня и ▷ для вложенных, но постепенно пришел к выводу, что отсутствие каких бы то ни было посторонних символов внутри сниппета существенно облегчает копирование фрагмента куда угодно. Поэтому так.
Цвета
Для поддержки тем оформления используется pry-theme
gem. Я использую раскраску синтаксиса (а когда надоедает, запускаю PRY_BW=true pry
). Для папок под управлением Rails (содержащих проекты Rails) цвета могут быть настроены еще причудливее, но я ненавижу Rails, и поэтому что там происходит, точно сказать не могу.
unless ENV['PRY_BW']
Pry.color = true
Pry.config.theme = "railscasts"
Pry.config.prompt = PryRails::RAILS_PROMPT if defined?(PryRails::RAILS_PROMPT)
Pry.config.prompt ||= Pry.prompt
end
История
Это просто находка. Находясь в режиме отладчика, или если команда была выполнена непосредственно перед этим, просто нажмите ⏎, и она будет повторена. Чрезвычайно полезно для перехода в код в отладчике (если вы, конечно, вообще пользуетесь отладчиком, а не фиксируете все ошибки пристальным взглядом, не запуская дебаггер никогда, как, например, я).
Pry.config.history.should_save = true
Pry::Commands.command /^$/, "repeat last command" do
_pry_.run_command Pry.history.to_a.last
end
Команды
Отладчик. Велосипед не мой, я просто позаимствовал эти пять строчек у своего товарища по команде, который проводит всю свою жизнь в отладке, но, говорят, работает.
Pry.commands.alias_command 'c', 'continue' rescue nil
Pry.commands.alias_command 's', 'step' rescue nil
Pry.commands.alias_command 'n', 'next' rescue nil
Pry.commands.alias_command 'f', 'finish' rescue nil
Pry.commands.alias_command 'l', 'whereami' rescue nil
Конфигурация описания модуля / класса
Pry.config.ls.separator = "\n" # new lines between methods
Pry.config.ls.heading_color = :magenta
Pry.config.ls.public_method_color = :green
Pry.config.ls.protected_method_color = :yellow
Pry.config.ls.private_method_color = :bright_black
Тут, вроде, и комментировать нечего.
Вызов системных утилит
Pry
поддерживает вызов системных утилит (просто добавьте точку перед именем команды без пробела, .ls
, или .ps axu
).
Плагины
Ниже приведен простейший пример настройки плагина. Никто не любит раздутые конфигурации, мы их отполировываем и таскаем за собой по разным машинами десятилетиями. Приведенный ниже фрагмент — лишь пример (для плагина awesome
). Комментарии в коде говорят сами за себя.
# `awesome_print` gem is a great syntax colorized printing
# look at `~/.aprc` for more settings for awesome_print
begin
require 'awesome_print'
# The following line enables awesome_print for all pry output,
# and it also enables paging
Pry.config.print = proc {|output, value| Pry::Helpers::BaseHelpers.stagger_output("=> #{value.ai}", output)}
# If you want awesome_print without automatic pagination, use the line below
module AwesomePrint
Formatter.prepend(Module.new do
def awesome_self(object, type)
return super(object, type) unless type == :string
return super(object, type) unless @options[:string_limit]
return super(object, type) unless object.inspect.to_s.length > @options[:string_limit]
colorize(object.inspect.to_s[0..@options[:string_limit]] + "...", type)
end
end)
end
AwesomePrint.defaults = {
:string_limit => 80,
:indent => 2,
:multiline => true
}
AwesomePrint.pry!
rescue LoadError => err
puts "gem install awesome_print # <-- highly recommended"
end
Пользовательские команды
Я уже говорил, что pry
очень крутой REPL? Мы даже можем определить свой собственный набор команд, которые будут использоваться внутри pry
. В приведенном ниже примере показано, как создать sql
-команду для выполнения чистого SQL из консоли (при условии, что у нас есть рабочее соединение AR) — с минимальным количеством нажатий клавиш.
default_command_set = Pry::CommandSet.new do
command "sql", "Send sql over AR." do |query|
if ENV['RAILS_ENV'] || defined?(Rails)
pp ActiveRecord::Base.connection.select_all(query)
else
pp "No rails env defined"
end
end
end
Pry.config.commands.import default_command_set
Monkeypatches и Globals
Да, мы можем настроить и выполнить любой код Ruby с помощью своих собственных monkeypatches, которые будут доступны только в сеансах pry
. Я, например, нахожу вот такой код весьма удобным для тестирования кода, оперирующего массивами и хэшами.
class Array
def self.sample(count = 10, &block)
Array.new(count, &(block || :succ))
end
end
Hash.singleton_class.prepend(Module.new
def sample(count = 10)
(?a...count.times.reduce(?a) { |o| o.succ }).
map(&:to_sym).zip(0...count).to_h
end
end)
Примечание: если вы думаете, что приведенный выше фрагмент переусложнен вот этим вот Integer#succ
, вы наверняка никогда не имели дело с длинными хэшами, имеющими более 26 ключей :)
Настройка цвета
Все, что ниже, предназначено для настройки цветов, используя coderay
gem. Результат того стоит. Символы красные, а цифры синие, и все такое прочее.
CodeRay.scan("example", :ruby).term # just to load necessary files
$LOAD_PATH << File.dirname(File.realpath(__FILE__))
require "escaped_colors"
module CodeRay
module Encoders
class Terminal < Encoder
TERM_TOKEN_COLORS.each_pair do |key, value|
TOKEN_COLORS[key] = value
end
end
end
end
В заключение
Я надеюсь, что эта заметка дает первое впечатление о том, что такое pry
, и почему оно лучше, чем irb
. Я не особо заострял внимание на процессе отладки, в основном потому, что я не отлаживаюсь, а пишу правильный код с нуля. Но я надеюсь, что смог заинтересовать тех, кто видит это сочетание букв — pry
— впервые — хотя бы попробовать. Поверьте, оно того сто́ит.
Удачных реплик!