Giter Club home page Giter Club logo

progress_bar's Introduction

ProgressBar

Build StatusGem Version

ProgressBar is a simple Ruby library for displaying progress of long-running tasks on the console. It is intended to be as simple to use as possible.

NOTE: This project isn't dead! It's just feature complete, and I don't want to keep adding things to it. If you find bugs, please open an Issue, or even better, a Pull Request, and I'll take a look. We at ProgressBar know you have lots of progress bar alternatives, and we thank you for using ProgressBar!

Installation

gem install progress_bar

Examples

The Easy Way

require 'progress_bar'

bar = ProgressBar.new

100.times do
  sleep 0.1
  bar.increment!
end

Produces output like:

[#######################################                           ] [ 59.00%] [00:06]

Note: It may not be exactly like this. I might have changed the default meters between now and when I wrote this readme, and forgotten to update it.

Setting the Max

Usually, the defaults should be fine, the only thing you'll need to tweak is the max.

bar = ProgressBar.new(1000)

Larger Steps

If you want to process several things, and update less often, you can pass a number to #increment!

    bar.increment! 42

Printing additional output

Sometimes you want to print some additional messages in the output, but since the ProgressBar uses terminal control characters to replace the text on the same line on every update, the output looks funny:

[#######################################                           ] [ 59.00%] [00:06]
Hello!
[#########################################                         ] [ 60.00%] [00:05]

To prevent this, you can use ProgressBar#puts so ProgressBar knows you want to print something, and it'll clear the bar before printing, then resume printing on the next line:

100.times do |i|
  sleep 0.1
  bar.puts "Halfway there!" if i == 50
  bar.increment!
end

Produces output like:

Halfway there!
[##################################] [100/100] [100%] [00:10] [00:00] [  9.98/s]

Try it out in examples/printing_messages.rb to see how it looks.

Picking the meters

By default, ProgressBar will use all available meters (this will probably change). To select which meters you want, and in which order, pass them to the constructor:

bar = ProgressBar.new(100, :bar, :rate, :eta)

Available Meters

  • :bar -- The bar itself, fills empty space with "#"s. Ex: [### ].
  • :counter -- Number of items complete, over the max. Ex: [ 20/100]
  • :percentage -- Percentage of items in the maximum. Ex: [ 42%]
  • :elapsed -- Time elapsed (since the ProgressBar was initialized. Ex: [00:42]
  • :eta -- Estimated Time remaining. Given the rate that items are completed, a guess at how long the rest will take. Ex: [01:30]
  • :rate -- The rate at which items are being completed. Ex: [ 42.42/s]

Run the tests to see examples of all the formats, with different values and maximums.

gem install --development progress_bar
rspec spec/*_spec.rb

Using ProgressBar on Enumerable-alikes.

If you do a lot of progresses, you can shorten your way with this:

class Array
  include ProgressBar::WithProgress
end

[1,2,3].each_with_progress{do_something}

# or any other Enumerable's methods:

(1..1000).to_a.with_progress.select{|i| (i % 2).zero?}

You can include ProgressBar::WithProgress in any class, having methods #count and #each, like some DB datasets and so on.

If you are using progress_bar regularly on plain arrays, you may want to do:

require 'progress_bar/core_ext/enumerable_with_progress'

# it adds each_with_progress/with_progress to Array/Hash/Range

(1..400).with_progress.select{|i| (i % 2).zero?}

If you want to display only specific meters you can do it like so:

(1..400).with_progress(:bar, :elapsed).select{|i| (i % 2).zero?}

progress_bar's People

Contributors

delta4d avatar hsbt avatar justinlove avatar koic avatar liljack avatar mmmries avatar notethan avatar panissupraomnia avatar paul avatar peterhellberg avatar phallstrom avatar slothbear avatar stevenharman avatar xtagon avatar zverok avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

progress_bar's Issues

Add Update/Replace/Set/etc. as alternative to Increment

I noticed this on a situation where I had the current progress, but not the exact difference between the current value and the last value I had. In my case it wasn't actually bad since it's just a simple count, but it feels wrong, and I can already see some situations where this could be a problem, the most obvious being asynchronous updates, a good example that comes to mind would be "how much data has already been received", but in my case I try to make my programs use STDIN/STDOUT as much as I can (Quite useful when you use grep, awk, wc, tail, etc.).

It'd be a simple update tolib/progress_bar.rb, a new function

  def update!(count = 1)
    self.count = count
    now = ::Time.now
    # last_write uses @, count uses self, it'd be nice to pick and use only one
    # also, you used || which means if either last_write is > 2 or @count is ABOVE max, it should write.
    if (now - @last_write) > 0.2 || self.count >= max
      write
      @last_write = now
    end
  end

Though I'd suggest refactoring some stuff, it's nice do consider it now since code is still quite simple, if it grows like this there'll be a lot of duplication.

Mostly it'd be a pain when adding stuff like different possible write conditions, different triggers for change, different output options/styles, and probably more. Also this is just an example, what matters is separation of concerns and each function doing only one thing. Plus, I didn't normalize but you should really decide on either @ or self or anything.

  # increment  and any functions that may appear (decrement?) should also be like this
  def update!(count = 1)
    self.count = count
    do_write
  end

#On private
  # if multiple branches, could either take arguments or use self./@
  def should_write? now
    slow_enough = (now - @last_write) > 0.2
    over_max = self.count >= max
    return true if slow_enough || over_max
    return false
  end
  def do_write
    now = ::Time.now
    return nil unless should_write? now # if !should_write also seems good.
    @last_write = time
    write
  end

Title?

Great progress, what about squeezing optional title on the left? Ideally ellipsized if there's no room?

lack of namespace causes issues with ruby-progressbar

Hi, could you consider moving ProgressBar to a namespace?

It's currently conflicting with ruby-progressbar, which also defines a top-level ProgressBar class. I use two different gems (Sunspot and minitest-reporters) which in turn depend on progress_bar and ruby-progressbar. This breaks things very subtly and caused quite a headache recently.

Thanks.

STDIN Conflict

Here is an example of my code that created a visual error, and the display to look funny. The progress bar still worked, and there is a work-around to stop the bug, but I thought I would mention it so that you can fix when you have the time...

q = Queue.new
ARGF.each_line do |line|
   (var1, var2) = line.split(",").map(&:chomp)
   q.push(MyClass.new(var1, var2)
end

bar = ProgressBar(q.size)
while not(q.empty?)
   ... do something
end

As you can see, I am reading a file from the command line, line by line, parsing it, and adding it to a queue. I am then using the ProgressBar to display processing of the data read. Now, ARGF allows me to provide files at the command line, or to pipe it to stdin. When I call my code as such:

$ cat datafile | myprogram.rb

It will display like so:

[root@dencts02 router-testing]# cat out.txt | ./check_routers
stty: standard input: Invalid argument
stty: standard input: Invalid argument 1/12] [  8.33%] [00:21] [03:58] [ 0.05/s]
stty: standard input: Invalid argument 2/12] [ 16.67%] [00:43] [03:37] [ 0.05/s]
stty: standard input: Invalid argument 3/12] [ 25.00%] [01:32] [04:38] [ 0.03/s]
stty: standard input: Invalid argument 4/12] [ 33.33%] [01:54] [03:48] [ 0.03/s]
stty: standard input: Invalid argument 5/12] [ 41.67%] [02:16] [03:10] [ 0.04/s]
stty: standard input: Invalid argument 6/12] [ 50.00%] [03:17] [03:17] [ 0.03/s]
stty: standard input: Invalid argument 7/12] [ 58.33%] [03:39] [02:36] [ 0.03/s]
stty: standard input: Invalid argument 8/12] [ 66.67%] [04:36] [02:18] [ 0.03/s]
stty: standard input: Invalid argument 9/12] [ 75.00%] [04:58] [01:39] [ 0.03/s]
stty: standard input: Invalid argument11/12] [ 91.67%] [05:04] [00:27] [ 0.04/s]
[##################################] [12/12] [100.00%] [05:28] [00:00] [ 0.04/s]

but if I call my program with a filename... then there is no problem:

$ myprogram.rb datafile
[#############################################] [12/12] [100.00%] [06:07] [00:00] [ 0.03/s]

It appears to get its knickers in a bunch if you are streaming in from STDIN.

Nice Gem, small minor non-critical bug

Resizing output window

This is not anything critical, but any resizing breaks the display due to wrapping issues.

Infinite progress bar

Hi,

I have a scenario where I'm iterating through a cursor but while I'm iterating I'm already processing the results.

So, there is a considerable delay between the scanning and the final, here's a pseudo-example:

x = Queue.new
bar = ProgressBar.new(Float::INFINITY)

Thread.new do
  i = 0

  cursor.each do |foo|
    x << foo
  end

  bar.total = i
  x.close
end

Thread.new do
  while (item = x.pop)
    process(item)
    bar.increment!
  end
end

Would be nice to have the progress bar in a state that says how many were processed but not the total/ETA yet while that.

Otherwise, I have to implement some dark magic to wait until the scan is done:

x = Queue.new
mutex = Mutex.new
processed = 0
total = 0
bar = nil

Thread.new do
  cursor.each do |foo|
    x << foo
    total += 1
  end

  mutex.synchronize do
    bar = ProgressBar.new(total)
    bar.increment!(processed)
  end
end

10.times do
  Thread.new do
     while (item = x.pop)
      process(item)
      mutex.synchronize do
        processed += 1
        bar&.increment!
      end
    end
  end

HighLine::SystemExtensions#terminal_size is a resource hog

I exchanged ruby-progressbar for progress_bar in an existing piece of code and ran a profiler (perftools.rb) on my code:

https://skitch.com/iconara/r4kqp/20110415095423.pdf-1-page

Updating the progress bar is 70% of the total run time, HighLine::SystemExtensions#terminal_size is the majority of that. The rest of the code does some heavy computation, so it is not the case that updating the progress bar is the only thing that is going on.

Shelling out many times per second is a really bad idea, it's incredibly slow.

Bar in some instances spans the whole terminal and in others only half

I'm having an issue where in one instance the bar will always cover the whole terminal (desired), but in another it will only take up half the terminal. In both cases they are instantiated with:

progress_bar = ProgressBar.new(array.length, :bar,:elapsed,:counter)

Though I was seeing the same behaviour when only passing in a total items value and using the full set of bar and metrics.
Progress_bar taking up the whole screen:
progress_bar_2

Progress_bar only taking up half the screen:
progress_bar_1

I wondered if it was determined by the with of lines above, so tried Putting a line of text the width of the whole terminal before the bar that is only taking up half the terminal, but it didn't have any effect.
This is replicable every time, with having made no changes to the terminal dimensions, Ubuntu 16.04, Gnome 3.18.3.

Bar duplicates/recreates itself at random intervals

Hi,
I've just had a go at using this bar to replace a bunch of terminal spam in a program I use for batching and compare graph sets.
It works great, love the various metrics you can include, but I've come a cross a couple of issues.
First one - While it's running it will usually but not always sort of jump the groove and create a new version of the bar graph and other metrics, keeping the progress, but leaving the partially filled version behind. It will do this multiple times on longer operations, but not at a consistent interval.
Terminal screen cap attached.
progress_bar_1

How I'm using it to cause the above :

                progress_bar = ProgressBar.new(images.length, :bar,:elapsed,:counter)
		done = false
		while images.length > 0
			image = images.pop
			total_count -=1
			Signal.trap("CLD") { counter += 1; progress_bar.increment! if !done}
			Process.wait if counter <= 0
			counter -= 1
			puts "#{total_count} images remaining" if !@quiet
			fork do
				if File.exist?("#{sets[0]}#{image}") && File.exist?("#{sets[1]}#{image}")
					return_ratio = compare_image_pair(["#{sets[0]}#{image}","#{sets[1]}#{image}"])
					out_file.puts "#{image}:#{return_ratio}"
				else
					puts "#{sets[0]}#{image}"
					puts "#{sets[1]}#{image}"
					puts "Unmatched file #{image}"
				end
				exit(0)
			end
		end
		Process.waitall
		puts "\nCompleted in #{Time.now - start_time} seconds with #{@max_processes} subprocesses"
		Process.waitall
		done = true
		progress_bar = nil 

Remove protected for ProgressBar methods.

To help people customize/extend ProgressBar for their specific use cases, it'd be great if there was no protected method access.

I'm wondering why those methods were protected in the first place?

More than happy to submit the 1 line PR if needed. ๐Ÿ‘๐Ÿป

ProgressBar fails to run on Heroku - negative argument

I'd like to use your progress bar gem in a long-running rake task for an app on Heroku, however it fails to initialize, likely because it is not getting the correct terminal width from HighLine. (Indeed, stty on Heroku reports zero rows and columns.)

rake aborted!
negative argument
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:97:in `*'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:97:in `render_bar'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:87:in `render'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:72:in `block in to_s'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:71:in `each'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:71:in `inject'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:71:in `to_s'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:35:in `write'
/app/.bundle/gems/ruby/1.9.1/gems/progress_bar-0.4.0/lib/progress_bar.rb:28:in `increment!'

This may yet be an issue to take up with Heroku, but I would think it's worthwhile to let you know here.

Happy to help if you have any questions.

"rake aborted! no such file to load -- options" error when running rake sunspot:reindex

This error occurs when using 'progress_bar' and 'terminitor' gems at the same time as they both have a dependency on the 'highline' gem, but with different version requirements.

Bundler could not find compatible versions for gem "highline":
In Gemfile:

progress_bar (>= 0) ruby depends on
  highline (~> 1.6.1) ruby

terminitor (~> 0.6.1) ruby depends on
  highline (1.5.2)

uninitialized constant ProgressBar::WithProgress

Hi, I want to use #with_progress but I can't

2.3.0 :001 > require 'progress_bar'
 => true
2.3.0 :002 > require 'progress_bar/with_progress'
LoadError: cannot load such file -- progress_bar/with_progress
    from /Users/lithium/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /Users/lithium/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from (irb):2
    from /Users/lithium/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
2.3.0 :003 > ProgressBar
 => ProgressBar
2.3.0 :004 > ProgressBar::WithProgress
NameError: uninitialized constant ProgressBar::WithProgress
    from (irb):4
    from /Users/lithium/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'

I check my ~/.rvm/gems/ruby-2.3.0/gems/progress_bar-1.0.5/ find there is no relative ruby files

use bundle exec irb fixed the issue.

Rate becomes inaccurate when count > max

I used to be able to use the rate display for a download with an unknown size. However, now it appears that my choices are to specify 1, and get a rate that asymptotically approaches 0, or something random like 10**10 (Infinity doesn't seem to work)

Running long tasks on heroku as a detached dyno

When running long tasks on heroku as detached one-off dyno as in:
heroku run:detached rake ns:task
The terminal is not connected to the task and all output is sent to heroku logs. This is useful if you are expecting a task to take hours or days and you can't sit and wait for it.
With progress_bar enabled tasks (like sunspot:reindex) monitoring the progress is impossible as the bar will only appear at the end (concatenated in the same line). I think this is because there is no new line character sent until at the very end.
Is there a way to allow this detached mode throw the current progress every minute or a configurable percentage?

warning: already initialized constant ProgressBar::Error

~ bundle exec rails c
2.3.0 :002 > require 'progress_bar/core_ext/enumerable_with_progress'
/root/server/HugoInvestServer/shared/bundle/ruby/2.3.0/bundler/gems/progress_bar-6dc27ba612bd/lib/progress_bar.rb:6: warning: already initialized constant ProgressBar::Error
/root/server/HugoInvestServer/releases/2031/vendor/bundle/ruby/2.3.0/bundler/gems/progress_bar-6dc27ba612bd/lib/progress_bar.rb:6: warning: previous definition of Error was here
/root/server/HugoInvestServer/shared/bundle/ruby/2.3.0/bundler/gems/progress_bar-6dc27ba612bd/lib/progress_bar.rb:7: warning: already initialized constant ProgressBar::ArgumentError
/root/server/HugoInvestServer/releases/2031/vendor/bundle/ruby/2.3.0/bundler/gems/progress_bar-6dc27ba612bd/lib/progress_bar.rb:7: warning: previous definition of ArgumentError was here

~ bundle exec irb

2.3.0 :001 > require 'progress_bar/core_ext/enumerable_with_progress'
 => true

in another rake file I have added require 'progress_bar'

solution is add

require 'progress_bar/core_ext/enumerable_with_progress'

into Rakefile and remove all the other requires

Sponsor button broken?

Hey, your sponsor button is broken.
I really love your work here, I would love to throw you a few $ man.

NaN exception when initializing with 0 and incrementing

[3] pry(main)> bar = ProgressBar.new(0)
=> #>,
   @key=nil,
   @menu=nil,
   @multi_indent=true,
   @output=#>,
   @page_at=nil,
   @prompt=nil,
   @question=nil,
   @wrap_at=nil>,
 @last_write=1970-01-01 01:00:00 +0100,
 @max=0,
 @meters=[:bar, :counter, :percentage, :elapsed, :eta, :rate],
 @start=2013-07-15 10:49:26 +0200>
[4] pry(main)> bar.increment!
FloatDomainError: NaN
from /Users/nicolas/.rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/progress_bar-1.0.0/lib/progress_bar.rb:98:in `ceil'

Printing to STDOUT

Hello, it seems as if the progress bar prints on STDERR instead of STDOUT.
If I run your example and redirect STDERR (ruby simple.rb 2>err.log), the progress bar isn't print on the console but to err.log.

Can that behavior be changed?

Prints progress on new line on windows

Hi - same problem as one or two other ruby progress bar gems.

Win7 64, ruby 1.9.3p429 (2013-05-15) [i386-mingw32]

[# ] [ 9.90/s] [00:09]
[## ] [ 9.97/s] [00:09]
[### ] [ 9.98/s] [00:09]
[##### ] [ 9.99/s] [00:09]
[###### ] [ 9.99/s] [00:09]
[####### ] [ 9.99/s] [00:08]
[######## ] [ 9.99/s] [00:08]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.