lib/progress.rb in progress-0.4.1 vs lib/progress.rb in progress-1.0.0
- old
+ new
@@ -10,21 +10,26 @@
if title.is_a?(Numeric) && total.nil?
title, total = nil, title
elsif total.nil?
total = 1
end
- total = Float(total)
- @title, @current, @total = title, 0.0, total == 0.0 ? 1.0 : total
+ @title = title
+ @current = 0.0
+ @total = total == 0.0 ? 1.0 : Float(total)
end
def step_if_blank
- self.current = 1.0 if current == 0.0 && total == 1.0
+ if current == 0.0 && total == 1.0
+ self.current = 1.0
+ end
end
def to_f(inner)
inner = [inner, 1.0].min
- inner *= current_step if current_step
+ if current_step
+ inner *= current_step
+ end
(current + inner) / total
end
def step(steps)
@current_step = steps
@@ -63,10 +68,14 @@
# ==== To output progress as lines (not trying to stay on line)
# Progress.lines = true
# ==== To force highlight
# Progress.highlight = true
def start(title = nil, total = nil)
+ if levels.empty?
+ @started_at = Time.now
+ @eta = nil
+ end
levels << new(title, total)
print_message(true)
if block_given?
begin
yield
@@ -74,36 +83,41 @@
stop
end
end
end
- def step(steps = 1)
+ def step(steps = 1, &block)
if levels.last
- if block_given?
- levels.last.step(steps) do
- yield
- end
- end
- levels.last.current += Float(steps)
- print_message
- elsif block_given?
- yield
+ set(levels.last.current + Float(steps), &block)
+ elsif block
+ block.call
end
end
- def set(value)
+ def set(value, &block)
if levels.last
+ ret = if block
+ levels.last.step(value - levels.last.current, &block)
+ end
levels.last.current = Float(value)
print_message
+ ret
+ elsif block
+ block.call
end
end
def stop
if levels.last
- print_message(true) if levels.last.step_if_blank || levels.length == 1
+ if levels.last.step_if_blank || levels.length == 1
+ print_message(true)
+ set_title(nil)
+ end
levels.pop
- io.puts if levels.empty?
+ if levels.empty?
+ io.puts
+ end
end
end
attr_writer :lines, :highlight # :nodoc:
@@ -132,46 +146,75 @@
def highlight?
@highlight.nil? ? io_tty? : @highlight
end
def time_to_print?
- if @previous
- if @previous < Time.now - 0.3
- @previous = Time.now
- true
- else
- false
- end
- else
+ if !@previous || @previous < Time.now - 0.3
@previous = Time.now
true
end
end
+ def eta(completed)
+ now = Time.now
+ if now > @started_at && completed > 0
+ current_eta = @started_at + (now - @started_at) / completed
+ @eta = @eta ? @eta + (current_eta - @eta) * (1 + completed) * 0.5 : current_eta
+ seconds = @eta - now
+ if seconds > 0
+ left = case seconds
+ when 0...60
+ '%.0fs' % seconds
+ when 60...3600
+ '%.1fm' % (seconds / 60)
+ when 3600...86400
+ '%.1fh' % (seconds / 3600)
+ else
+ '%.1fd' % (seconds / 86400)
+ end
+ eta_string = " (ETA: #{left})"
+ end
+ end
+ end
+
+ def set_title(title)
+ if io_tty?
+ io.print("\e]0;#{title}\a")
+ end
+ end
+
def print_message(force = false)
if force || time_to_print?
- messages = []
inner = 0
+ parts = []
+ parts_cl = []
levels.reverse.each do |l|
current = l.to_f(inner)
value = current == 0 ? '......' : "#{'%5.1f' % (current * 100.0)}%"
- messages << "#{"#{l.title}: " if l.title}#{!highlight? || value == '100.0%' ? value : "\e[1m#{value}\e[0m"}"
inner = current
+
+ title = l.title ? "#{l.title}: " : ''
+ highlighted = "\e[1m#{value}\e[0m"
+ if !highlight? || value == '100.0%'
+ parts << "#{title}#{value}"
+ else
+ parts << "#{title}#{highlighted}"
+ end
+ parts_cl << "#{title}#{value}"
end
- message = messages.reverse * ' > '
+ eta_string = eta(inner)
+ message = "#{parts.reverse * ' > '}#{eta_string}"
+ message_cl = "#{parts_cl.reverse * ' > '}#{eta_string}"
+
unless lines?
previous_length = @previous_length || 0
- message_cl = if highlight?
- message.gsub(/\033\[(0|1)m/, '')
- else
- message
- end
@previous_length = message_cl.length
message = "#{message}#{' ' * [previous_length - message_cl.length, 0].max}\r"
end
lines? ? io.puts(message) : io.print(message)
+ set_title(message_cl)
end
end
end
end