Использование BacktraceCleaner в консоли Rails?

Я использую консоль Rails в режиме отладки довольно много, и ее просто немного утомительно, чтобы изменить размер окна консоли, чтобы я мог найти верхнюю часть списка без необходимости прокрутки.

Я думал, что BacktraceCleaner может с этим справиться, но я не могу заставить его ничего не слышать в консоли.

Я помещаю этот код в инициализатор в своем приложении.

bc = Rails.backtrace_cleaner
bc.add_filter { |line| line.gsub(Rails.root.to_s, '<root>') }
bc.add_silencer { |line| line.index('<root>').nil? and line.index('/') == 0 }
bc.add_silencer { |line| line.index('<root>/vendor/') == 0 }
bc.add_silencer { |line| line =~ /console.rb/ }
bc.add_silencer { |line| line =~ /ruby-debug.ide.rb/ }
bc.add_silencer { |line| line =~ /rdebug-ide/ }

но не влияет на ошибки консоли. Поэтому я попробовал его прямо в консоли:

>>bc = Rails.backtrace_cleaner
>>bc.add_silencer { |line| line =~ /console.rb/ }
>> 1/0
   ZeroDivisionError: divided by 0
from (irb):23:in `/'
from (irb):23
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-4.0.3/lib/rails/commands /console.rb:90:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-4.0.3/lib/rails/commands/console.rb:9:in `start'

- и все еще видя обратные линии, содержащие "console.rb". Rails.backtrace_cleaner возвращает другое другое средство очистки, которое не используется в среде консоли Rails?

Как я могу получить дескриптор (или установки) очистителя backtrace на консольных backtraces?

Ответ 1

Проблема заключается в том, что консоль IRB реализует собственный шумоглушитель Backtrace, который отличается от Rails. Но он может быть переопределен IRB.

Из исходного кода IRB видно, что глушитель который вызывается здесь, используя метод filter_backtrace из класс WorkSpace. Таким образом, мы можем исправить этот метод, чтобы использовать глушитель Rails поверх IRB по умолчанию.

Патч может быть помещен в инициализатор Rails, но более чистым подходом, на мой взгляд, является использование переменной конфигурации IRB_RC, которая может быть установлена ​​на любой код ruby ​​и что будет вызываться во время инициализации IRB. Таким образом, мы сохраним патч в контексте IRB и не повлияем на код приложения Rails.

Следующий код отправляется в ~/.irbrc:

if ENV['RAILS_ENV']

  # silence console backtraces using BacktraceSilencer from Rails
  IRB.conf[:IRB_RC] = Proc.new do

    class IRB::WorkSpace
      alias_method :orig_filter_backtrace, :filter_backtrace

      def filter_backtrace(bt)
        filtered_bt = orig_filter_backtrace(bt)

        # The Rails silencer operates on the whole backtrace therefore
        # we need to temporarily convert the particular trace line to an array
        rails_backtrace_cleaner.clean(Array(filtered_bt)).first
      end

      private

      def rails_backtrace_cleaner
        Rails.backtrace_cleaner
      end

    end
  end
end

Как прокомментировано в коде, нам нужно иметь дело с одной небольшой проблемой - глушитель Rails работает на всей backtrace (передается как массив строк), тогда как метод блокировки IRB вызывается для каждой строки отдельно. Вот почему строка временно преобразуется в массив до перехода к глушителю Rails.

Если вы действительно хотите, чтобы пользовательский глушитель, а не Rails, вместо этого использовал что-то вроде этого:

  def rails_backtrace_cleaner                                  
    @rails_backtrace_cleaner ||= begin
      bc = ActiveSupport::BacktraceCleaner.new
      bc.add_filter { |line| line.gsub(Rails.root.to_s, '<root>') }
      bc.add_silencer { |line| line.index('<root>').nil? and line.index('/') == 0 }
      bc.add_silencer { |line| line.index('<root>/vendor/') == 0 }
      bc.add_silencer { |line| line =~ /console.rb/ }
      bc.add_silencer { |line| line =~ /ruby-debug.ide.rb/ }
      bc.add_silencer { |line| line =~ /rdebug-ide/ }
      bc
    end
  end

Тест (с глушителем Rails по умолчанию)

$ rails c
Loading development environment (Rails 4.2.5.1)
>> 1/0
ZeroDivisionError: divided by 0    
>>

Пример с исключением, вызванным внутри метода модели:

$ rails c
Loading development environment (Rails 4.2.5.1)
>> BaseUser.find(1234).update_rating
RuntimeError: Exception occured!
  from app/models/base_user.rb:51:in `update_rating'
>> 

Как видно, Rails внутренние строки stttrace отключены, а корневые пути Rails отфильтровываются.