Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/usr/bin/ruby
class ProgressMeter
attr_accessor :progress, :total
def initialize( total = 1 )
@progress, @total = 0, total
@old_str_size = 0
end
def run( total = nil, &blk )
@total = total if total
@start_time = Time.now
$stdout.sync = true
while @progress < @total do
yield
@progress += 1
update
end
puts
end
protected
def update
if @progress >= @total
print_in_place "done (#{total} over #{Time.now - @start_time}s)"
return
end
eta = (Time.now - @start_time) * ((@total.to_f / @progress) - 1.0)
print_in_place( '%i/%i (%.1f%%) ETA: %s' % [@progress, @total, 100.0 * @progress / @total, format_duration(eta)] )
end
def print_in_place( str )
print( "\b" * @old_str_size, str )
extra = @old_str_size - str.size
print( ' ' * extra, "\b" * extra ) if extra > 0
@old_str_size = str.size
end
# taken from ActiveSupport
def format_duration( duration )
distance_in_minutes = (duration.abs / 60).round
distance_in_seconds = duration.abs.round
case distance_in_minutes
when 0..1
case distance_in_seconds
when 0..4 then 'less than 5 seconds'
when 5..9 then 'less than 10 seconds'
when 10..19 then 'less than 20 seconds'
when 20..39 then 'half a minute'
when 40..59 then 'less than 1 minute'
else '1 minute'
end
when 2..44 then "#{distance_in_minutes} minutes"
when 45..89 then 'about 1 hour'
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
when 1440..2879 then '1 day'
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
when 43200..86399 then "about 1 month"
when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
when 525600..1051199 then "about 1 year"
else "over #{(distance_in_minutes / 525600).round} years"
end
end
end
print 'Doing stuff ... '
ProgressMeter.new.run( 100 ) do
sleep 0.1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.