multi_progress_bar 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +11 -0
- data/Rakefile +27 -0
- data/examples/example.rb +35 -0
- data/examples/loop.rb +40 -0
- data/lib/multi_progress_bar/bar.rb +53 -0
- data/lib/multi_progress_bar/bar_renderer.rb +22 -0
- data/lib/multi_progress_bar/total_bar.rb +32 -0
- data/lib/multi_progress_bar.rb +59 -0
- metadata +63 -0
data/README.rdoc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
== MultiProgressBar
|
2
|
+
|
3
|
+
Displays multiple progress bars using Ncurses. Useful for displaying the status of multiple test runs, say, distributed across different machines. Which is exactly why I wrote it.
|
4
|
+
|
5
|
+
Uses +ruby-progressbar+ to render the bars.
|
6
|
+
|
7
|
+
== Credits
|
8
|
+
|
9
|
+
* Codes by Peter Jaros.
|
10
|
+
* Thanks to Nick Evans for the inspiration (http://ekenosen.net/nick/devblog/2008/12/better-progress-bar-for-rspec/).
|
11
|
+
* Thanks to Satoru Takabayashi for +ruby-progressbar+ (http://0xcc.net/ruby-progressbar/index.html.en).
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "multi_progress_bar"
|
5
|
+
gemspec.summary = "Displays multiple progress bars using Ncurses."
|
6
|
+
gemspec.description = "Displays multiple progress bars using Ncurses. Useful for displaying the status of multiple test runs, say, distributed across different machines. Which is exactly why I wrote it."
|
7
|
+
gemspec.email = "peter.a.jaros@gmail.com"
|
8
|
+
gemspec.homepage = "http://github.com/Peeja/multi_progress_bar/tree/master/"
|
9
|
+
gemspec.authors = ["Peter Jaros"]
|
10
|
+
end
|
11
|
+
rescue LoadError
|
12
|
+
puts "Jeweler not available. For gem tasks, install it with: sudo gem install jeweler"
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
begin
|
17
|
+
require 'hanna/rdoctask'
|
18
|
+
rescue LoadError
|
19
|
+
require 'rake/rdoctask'
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Generate RDoc documentation.'
|
23
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
24
|
+
rdoc.main = "README.rdoc"
|
25
|
+
rdoc.rdoc_dir = 'doc'
|
26
|
+
rdoc.options << '--webcvs=http://github.com/Peeja/multi_progress_bar/tree/master/'
|
27
|
+
end
|
data/examples/example.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)+"/../lib"
|
6
|
+
require 'multi_progress_bar'
|
7
|
+
|
8
|
+
|
9
|
+
begin
|
10
|
+
MultiProgressBar.start
|
11
|
+
|
12
|
+
# Demo.
|
13
|
+
make_machine_bar = lambda { MultiProgressBar::Bar.new("(Waiting...)", 100) }
|
14
|
+
machine_bars = [make_machine_bar[], make_machine_bar[]]
|
15
|
+
total = MultiProgressBar::TotalBar.new("-Total-")
|
16
|
+
|
17
|
+
machine_names = ["bleeker", "montrose"]
|
18
|
+
|
19
|
+
until machine_bars.all? { |bar| bar.current == bar.total }
|
20
|
+
sleep(0.1)
|
21
|
+
|
22
|
+
# Simulate machines becoming available.
|
23
|
+
machine_bars.each do |bar|
|
24
|
+
if bar.title == "(Waiting...)"
|
25
|
+
bar.title = machine_names.pop if rand(10) == 0
|
26
|
+
else
|
27
|
+
bar.inc(rand(10))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
MultiProgressBar.log(rand(2000))
|
32
|
+
end
|
33
|
+
ensure
|
34
|
+
MultiProgressBar.end
|
35
|
+
end
|
data/examples/loop.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# Not actually an example, but a script to run the example every
|
4
|
+
# time a file changes, for testing.
|
5
|
+
#
|
6
|
+
# example/loop example/example.rb
|
7
|
+
|
8
|
+
command = ARGV.shift
|
9
|
+
file_patterns_to_watch = (ARGV.length > 0 ? ARGV : ['**/*.rb'])
|
10
|
+
|
11
|
+
files = {}
|
12
|
+
|
13
|
+
file_patterns_to_watch.each do |arg|
|
14
|
+
Dir[arg].each { |file|
|
15
|
+
files[file] = File.mtime(file)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
trap('INT') do
|
20
|
+
puts "\nQuitting..."
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
loop do
|
26
|
+
system command
|
27
|
+
|
28
|
+
loop do
|
29
|
+
sleep 0.1
|
30
|
+
|
31
|
+
changed_file, last_changed = files.find { |file, last_changed|
|
32
|
+
File.mtime(file) > last_changed
|
33
|
+
}
|
34
|
+
|
35
|
+
if changed_file
|
36
|
+
files[changed_file] = File.mtime(changed_file)
|
37
|
+
break
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module MultiProgressBar
|
2
|
+
# Represents a progress bar at the bottom of the screen.
|
3
|
+
#
|
4
|
+
# +Bar+ exposes the same interface as +ProgressBar+ from the +progressbar+
|
5
|
+
# gem which backs its display.
|
6
|
+
#
|
7
|
+
# file_progress = MultiProgressBar::Bar.new("file_1", 2596)
|
8
|
+
# file_progress.inc # Increment value by 1.
|
9
|
+
# file_progress.inc(10) # Increment value by 10.
|
10
|
+
# file_progress.set(30) # Set value to 30.
|
11
|
+
#
|
12
|
+
# # Change bar format.
|
13
|
+
# file_progress.format = "%-14s (%s) %3d%% %s"
|
14
|
+
# file_progress.format_arguments = [:title, :stat, :percentage, :bar].
|
15
|
+
#
|
16
|
+
# See the +ruby-progressbar+ gem (http://0xcc.net/ruby-progressbar/index.html.en)
|
17
|
+
# for more details.
|
18
|
+
class Bar < DelegateClass(BarRenderer)
|
19
|
+
# Create a new Bar with a +title+ and a +total+ value.
|
20
|
+
def initialize(title, total)
|
21
|
+
MultiProgressBar.add_bar(self)
|
22
|
+
|
23
|
+
@observers = []
|
24
|
+
|
25
|
+
@renderer = BarRenderer.new(title, total, MultiProgressBar.width) do |rendered_bar|
|
26
|
+
MultiProgressBar.update_bar(self, rendered_bar)
|
27
|
+
end
|
28
|
+
|
29
|
+
super @renderer
|
30
|
+
end
|
31
|
+
|
32
|
+
# Increment the current value of the bar.
|
33
|
+
def inc(step = 1)
|
34
|
+
super
|
35
|
+
notify_observers
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set the current value of the bar absolutely.
|
39
|
+
def set(count)
|
40
|
+
super
|
41
|
+
notify_observers
|
42
|
+
end
|
43
|
+
|
44
|
+
def observe(&b) #:nodoc:
|
45
|
+
@observers << b
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def notify_observers
|
50
|
+
@observers.each { |b| b.call(self) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module MultiProgressBar
|
2
|
+
class BarRenderer < ProgressBar #:nodoc:
|
3
|
+
attr_writer :title
|
4
|
+
|
5
|
+
def initialize(title, total, width, &block)
|
6
|
+
@block = block
|
7
|
+
@buffer = StringIO.new
|
8
|
+
@width = width
|
9
|
+
super(title, total, @buffer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def show
|
13
|
+
super
|
14
|
+
@block.call(@buffer.string)
|
15
|
+
@buffer.string = ""
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_width
|
19
|
+
@width
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module MultiProgressBar
|
2
|
+
# Works just like +Bar+, but displays the total of other bars.
|
3
|
+
# TotalBar#inc and TotalBar#set don't work.
|
4
|
+
class TotalBar < Bar
|
5
|
+
# Create a new TotalBar. +bars+ is an array of Bar objects, and defaults to
|
6
|
+
# all existing bars.
|
7
|
+
def initialize(title, bars = MultiProgressBar.bars.dup)
|
8
|
+
@bars = bars
|
9
|
+
|
10
|
+
@bars.each do |bar|
|
11
|
+
bar.observe do
|
12
|
+
update_total
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
total_total = @bars.inject(0) { |sum, bar| sum + bar.total }
|
17
|
+
super title, total_total
|
18
|
+
end
|
19
|
+
|
20
|
+
[:inc, :set].each do |name|
|
21
|
+
define_method(name) do
|
22
|
+
raise NoMethodError, "NoMethodError: private method `#{name}' called for #{self}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def update_total
|
28
|
+
total_current = @bars.inject(0) { |sum, bar| sum + bar.current }
|
29
|
+
@renderer.set(total_current)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'ncurses'
|
2
|
+
require 'progressbar'
|
3
|
+
require 'delegate'
|
4
|
+
require 'abstraction'
|
5
|
+
|
6
|
+
module MultiProgressBar
|
7
|
+
class << self
|
8
|
+
attr_reader :bars
|
9
|
+
|
10
|
+
# Set up the screen. Always call +MultiProgressBar.start+ before using progress bars.
|
11
|
+
def start
|
12
|
+
@bars = [].freeze
|
13
|
+
|
14
|
+
Ncurses.initscr
|
15
|
+
Ncurses.curs_set(0)
|
16
|
+
|
17
|
+
@bars_window = Ncurses::WINDOW.new(1, 0, Ncurses.LINES-1, 0)
|
18
|
+
@log_window = Ncurses::WINDOW.new(Ncurses.LINES-1, 0, 0, 0)
|
19
|
+
@log_window.scrollok(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Restore the terminal to normal function. Always call this before exiting.
|
23
|
+
def end
|
24
|
+
Ncurses.endwin
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
|
28
|
+
# Write +text+ to the space above the progress bars.
|
29
|
+
def log(text)
|
30
|
+
@log_window.addstr("#{text}\n")
|
31
|
+
@log_window.refresh
|
32
|
+
end
|
33
|
+
|
34
|
+
def width #:nodoc:
|
35
|
+
@bars_window.getmaxx
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_bar(bar) #:nodoc:
|
39
|
+
@bars += [bar]
|
40
|
+
|
41
|
+
@bars_window.mvwin(Ncurses.LINES-bars.size, @bars_window.getbegx)
|
42
|
+
@bars_window.resize(bars.size, @bars_window.getmaxx)
|
43
|
+
@bars_window.refresh
|
44
|
+
|
45
|
+
@log_window.resize(Ncurses.LINES-bars.size, @log_window.getmaxx)
|
46
|
+
@log_window.refresh
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_bar(bar, rendered_bar) #:nodoc:
|
50
|
+
@bars_window.move(bars.index(bar), 0)
|
51
|
+
@bars_window.addstr(rendered_bar)
|
52
|
+
@bars_window.refresh
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
require 'multi_progress_bar/bar_renderer'
|
58
|
+
require 'multi_progress_bar/bar'
|
59
|
+
require 'multi_progress_bar/total_bar'
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multi_progress_bar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Jaros
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-15 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Displays multiple progress bars using Ncurses. Useful for displaying the status of multiple test runs, say, distributed across different machines. Which is exactly why I wrote it.
|
17
|
+
email: peter.a.jaros@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- README.rdoc
|
26
|
+
- Rakefile
|
27
|
+
- examples/example.rb
|
28
|
+
- examples/loop.rb
|
29
|
+
- lib/multi_progress_bar.rb
|
30
|
+
- lib/multi_progress_bar/bar.rb
|
31
|
+
- lib/multi_progress_bar/bar_renderer.rb
|
32
|
+
- lib/multi_progress_bar/total_bar.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://github.com/Peeja/multi_progress_bar/tree/master/
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --charset=UTF-8
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.3.5
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Displays multiple progress bars using Ncurses.
|
61
|
+
test_files:
|
62
|
+
- examples/example.rb
|
63
|
+
- examples/loop.rb
|