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