Progress bar для скриптов на Ruby

07 декабря 2010, обновлена 01 января 2011

Знакома такая ситуация – пишешь задачу для Rake, понимаешь, что выполняться она будет долго, а сделать какую-нибудь индикацию процесса облом?

Ну или если уж приходится делать, знаком такой вот код?

count=0
some_long_data_array.each do |data|
  data.process
  count+=1
  puts "#{count}/#{some_long_data_array.length}" if (count%1000)==0
end

Посчитай – тут половина строчек занимается выводом статистики! Да еще и не очень полезной. Вот мне и захотелось решить это проблему «сухим» и универсальным способом.

Надо сказать, что ее решили еще в 2005 году, и этот скрипт для вывода индикатора выполнения практически без изменений используется и до сих пор в виде гема ruby-progressbar. С ним можно написать вот так:

require 'progressbar'
pbar = ProgressBar.new('data processing', some_long_data_array.length)
some_long_data_array.each do |data|
  data.process
  pbar.inc
end
pbar.finish

Строчек не поубавилось, зато благодаря ruby-progressbar мы получаем красивенький индикатор выполнения:

data processing:           67% |oooooooooooooooooooooooooo              | ETA:  00:00:03

Как видишь, тут даже показывается ориентировочное время до окончания операции. Удобно!

Естественно, библиотека, написанная в 2005, не использует современных идиом Ruby (да она даже RDoc не использует), что я и постарался изменить.

Итак, мой форк гема ruby-progressbar, помимо вышеописанного, поддерживает блочную форму вызова:

require 'progressbar'
ProgressBar.block('data processing', some_long_data_array.length) do |pbar|
  some_long_data_array.each do |data|
    data.process
    pbar.inc
  end
end

Но и это еще не все! В 90% случаев обработка данных происходит в виде одного из методов-итераторов Enumerable – почему бы тогда высушить код еще дальше?

require 'progressbar'
some_long_data_array.each_with_progressbar('data processing') do |data|
  data.process
end
# or map_with_progressbar, or select_with_progressbar, etc

Сложно сделать этот код еще короче, не так ли?

Кроме того, я, следуя правилу бойскаутов, задокументировал код посредством RDoc и выполнил рефакторинг.

Установка

Предполагая, что ты используешь bundler:

# Gemfile
gem 'ruby-progressbar', :git => 'git://github.com/leonid-shevtsov/ruby-progressbar.git'

И – вперед, к наглядным Rake-таскам и аккуратному коду!



Один комментарий. Напиши еще один
  1. Edea246ed0b71f4e5f21ea785e2da383 # 10 декабря 2010 gonzo (gonzo.kiev.ua) написал:

    Я буквально пару дней назад хотел, что-то такое, но лень было гуглить :)
    А можно все посты отсчета пометить каким-нибудь тэгом, чтобы одна ссылка на все сразу была?

(нужна разметка?)

  • **жирный**
  • > цитата

отменить