Skip to content

Commit

Permalink
Change to fix premature finish of top level multi bar and closes #22
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrmurach committed Sep 9, 2017
1 parent 98a7803 commit c53b719
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 20 deletions.
41 changes: 29 additions & 12 deletions lib/tty/progressbar/multi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def initialize(*args)
@bars = []
@rows = 0
@top_bar = nil
@top_bar = register(format) if format
@top_bar = register(format, observable: false) if format

@callbacks = {
progress: [],
Expand All @@ -66,15 +66,15 @@ def initialize(*args)
#
# @api public
def register(format, options = {})
observable = options.delete(:observable) { true }
bar = TTY::ProgressBar.new(format, @options.merge(options))

synchronize do
bar.attach_to(self)
@bars << bar

observe(bar) if observable
if @top_bar
@top_bar.update(total: total, width: total)
observe(bar)
end
end

Expand All @@ -95,11 +95,21 @@ def next_row
# @param [TTY::ProgressBar] bar
# the bar to observe for events
#
# @api public
# @api private
def observe(bar)
bar.on(:progress) { top_bar.current = current; emit(:progress) }
.on(:done) { top_bar.finish; emit(:done) if complete? }
.on(:stopped) { top_bar.stop; emit(:stopped) if stopped? }
bar.on(:progress, &progress_handler)
.on(:done) { emit(:done) if complete? }
.on(:stopped) { emit(:stopped) if stopped? }
end

# Handle the progress event
#
# @api private
def progress_handler
proc do
@top_bar.current = current if @top_bar
emit(:progress)
end
end

# Get the top level bar if it exists
Expand All @@ -123,7 +133,9 @@ def start
#
# @api public
def total
(@bars - [@top_bar]).dup.map(&:total).reduce(&:+)
synchronize do
(@bars - [@top_bar]).dup.map(&:total).reduce(&:+)
end
end

# Calculate total current progress of all bars
Expand All @@ -132,7 +144,9 @@ def total
#
# @api public
def current
(@bars - [@top_bar]).dup.map(&:current).reduce(&:+)
synchronize do
(@bars - [@top_bar]).dup.map(&:current).reduce(&:+)
end
end

# Check if all progress bars are complete
Expand All @@ -141,7 +155,9 @@ def current
#
# @api public
def complete?
(@bars - [@top_bar]).dup.all?(&:complete?)
synchronize do
(@bars - [@top_bar]).dup.all?(&:complete?)
end
end

# Check if any of the registered progress bars is stopped
Expand All @@ -150,7 +166,9 @@ def complete?
#
# @api public
def stopped?
(@bars - [@top_bar]).dup.any?(&:stopped?)
synchronize do
(@bars - [@top_bar]).dup.any?(&:stopped?)
end
end

# Stop all progress bars
Expand All @@ -164,7 +182,6 @@ def stop
#
# @api public
def finish
@top_bar.finish if @top_bar
@bars.dup.each(&:finish)
end

Expand Down
67 changes: 60 additions & 7 deletions spec/unit/multi/events_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
RSpec.describe TTY::ProgressBar::Multi, 'events' do
let(:output) { StringIO.new('', 'w+') }

it "emits :progress eent when any of the registerd bars advances" do
it "emits :progress event when any of the registerd bars advances" do
events = []
bars = TTY::ProgressBar::Multi.new("[:bar]", output: output, total: 5)
bars.on(:progress) { events << :progress }
Expand All @@ -14,31 +14,57 @@
expect(events).to eq([:progress])
end

it "emits :done event when all progress bars finished" do
it "emits :done event when all progress bars finished under top level" do
events = []
bars = TTY::ProgressBar::Multi.new("[:bar]", output: output, total: 5)
bars.on(:done) { events << :done }

bar = bars.register "one [:bar]"

bar.finish

expect(events).to eq([:done])
expect(bar.complete?).to eq(true)
end

it "emits :done event when top level bar finished" do
it "emits :done event when all progress bars finished without top level" do
events = []
bars = TTY::ProgressBar::Multi.new(output: output)
bars.on(:done) { events << :done }
bar = bars.register "one [:bar]", total: 5

bar.finish

expect(events).to eq([:done])
expect(bars.complete?).to eq(true)
end

it "emits :done event when top level registered bar finished" do
events = []
bars = TTY::ProgressBar::Multi.new("[:bar]", output: output, total: 5)
bars.on(:done) { events << :done }

bars.register "one [:bar]"
bar = bars.register "one [:bar]", total: 5

bars.finish

expect(events).to eq([:done])
expect(bar.complete?).to eq(true)
end

it "emits :stopped event when all registerd bars are stopped" do
it "emits :done event when top level bar finished" do
events = []
bars = TTY::ProgressBar::Multi.new(output: output)
bars.on(:done) { events << :done }

bar = bars.register "one [:bar]", total: 5

bars.finish

expect(events).to eq([:done])
expect(bar.complete?).to eq(true)
end

it "emits :stopped event when all registerd bars are stopped under top level" do
events = []
bars = TTY::ProgressBar::Multi.new("[:bar]", output: output, total: 5)
bars.on(:stopped) { events << :stopped }
Expand All @@ -48,9 +74,23 @@
bar.stop

expect(events).to eq([:stopped])
expect(bars.stopped?).to eq(true)
end

it "emits :stopped event when all registerd bars are stopped without top level" do
events = []
bars = TTY::ProgressBar::Multi.new(output: output)
bars.on(:stopped) { events << :stopped }

bar = bars.register "one [:bar]", total: 5

bar.stop

expect(events).to eq([:stopped])
expect(bars.stopped?).to eq(true)
end

it "emits :stopped event when top level bar finished" do
it "emits :stopped event when registerd multi bar finished" do
events = []
bars = TTY::ProgressBar::Multi.new("[:bar]", output: output, total: 5)
bars.on(:stopped) { events << :stopped }
Expand All @@ -61,4 +101,17 @@

expect(events).to eq([:stopped])
end

it "emits :stopped event when multi bar finished" do
events = []
bars = TTY::ProgressBar::Multi.new(output: output)
bars.on(:stopped) { events << :stopped }

bars.register "one [:bar]", total: 5

bars.stop

expect(events).to eq([:stopped])
expect(bars.stopped?).to eq(true)
end
end
26 changes: 25 additions & 1 deletion spec/unit/multi/finish_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
RSpec.describe TTY::ProgressBar::Multi, '#finish' do
let(:output) { StringIO.new('', 'w+') }

it "finishes all bars" do
it "finishes all bars with top level" do
bars = TTY::ProgressBar::Multi.new("main [:bar]", output: output)

bar1 = bars.register("[:bar]", total: 5)
Expand All @@ -16,4 +16,28 @@

expect(bars.complete?).to eq(true)
end

it "finishes all bars without top level" do
bars = TTY::ProgressBar::Multi.new(output: output)

bar1 = bars.register("[:bar]", total: 5)
bar2 = bars.register("[:bar]", total: 10)

bar1.finish
bar2.finish

expect(bars.complete?).to eq(true)
end

it "finishes top level" do
bars = TTY::ProgressBar::Multi.new(output: output)

bar1 = bars.register("[:bar]", total: 5)
bar2 = bars.register("[:bar]", total: 10)

bars.finish

expect(bar1.complete?).to eq(true)
expect(bar2.complete?).to eq(true)
end
end
1 change: 1 addition & 0 deletions spec/unit/multi/register_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
it "uses global options to register instance" do
bars = TTY::ProgressBar::Multi.new(output: output, total: 100)
bar = double(:bar, attach_to: nil)
allow(bar).to receive(:on).and_return(bar)
allow(TTY::ProgressBar).to receive(:new).and_return(bar)

bars.register("[:bar]")
Expand Down

0 comments on commit c53b719

Please sign in to comment.