REPL


REPL в мире наколенной разработки расшифровывается как Read → Evaluate → Print Loop. Зачитали, выполнили, напечатали, и так много раз.


Ruby, как и многие другие языки, поставляется с собственной реализацией REPL под названием irb. Который, хотя и справляется с примитивными задачами, все-таки полностью удовлетворить запросы взыскательного разработчика не может. Но существует и гораздо более развитая альтернатива: pry.


Pry Logo


Вот рекламный отрывок с официального сайта 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.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 — впервые — хотя бы попробовать. Поверьте, оно того сто́ит.


Удачных реплик!

Комментарии (0)