Progress bar для скриптов на Ruby
December 8, 2010 , revised January 1, 2011 in Ruby on RailsЗнакома такая ситуация - пишешь задачу для 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-таскам и аккуратному коду!
Понравился пост? Купи мне кофе