Skip to content

Commit

Permalink
Add manual_stop option
Browse files Browse the repository at this point in the history
  • Loading branch information
KevSlashNull committed Jul 22, 2024
1 parent ea9be11 commit 5ff5412
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 3 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,18 @@ The result may look like this:
└── [✖] two
```

If you wish to also have manual control over the top-level spinner, set
the `manual_stop` option. This keeps the top-level spinner spinning even
if all currently registered spinners have finished. You can then, for
example, add more spinners or call `multi_spinner.success` even if a
spinner has errored.

```ruby
multi_spinner = TTY::Spinner::Multi.new("[:spinner] top", manual_stop: true)
```

See also the `examples/multi/multi_manual_stop.rb` example.

#### 5.2.2 auto async tasks

In case when you wish to execute async tasks and update individual spinners automatically, in any order, about their task status use `#register` and pass additional block parameter with the job to be executed.
Expand Down
25 changes: 25 additions & 0 deletions examples/multi/multi_manual_stop.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

require_relative "../../lib/tty-spinner"

spinners = TTY::Spinner::Multi.new("[:spinner] Top level spinner",
manual_stop: true)

sp1 = spinners.register "[:spinner] one"
sp1.auto_spin

sleep(2)
sp1.success

sp2 = spinners.register "[:spinner] two"
sp3 = spinners.register "[:spinner] three"

sp2.auto_spin
sp3.auto_spin

sleep(1)
sp2.error
sleep(1)
sp3.success

spinners.error # requires manual stop
17 changes: 14 additions & 3 deletions lib/tty/spinner/multi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ class Multi
# clear ouptut when finished
# @option options [Float] :interval
# the interval for auto spinning
# @option options [Boolean] :manual_stop
# the top spinner (if present) doesn't automatically stop when all
# registered spinners have finished, allowing new spinners to be
# added after that.
#
# @api public
def initialize(*args)
super()
@options = args.last.is_a?(::Hash) ? args.pop : {}
message = args.empty? ? nil : args.pop
@inset_opts = @options.delete(:style) { DEFAULT_INSET }
@manual_stop = @options.fetch(:manual_stop) { false }
@rows = 0
@spinners = []
@spinners_count = 0
Expand Down Expand Up @@ -112,7 +117,7 @@ def create_spinner(pattern_or_spinner, options)
pattern_or_spinner
else
raise ArgumentError, "Expected a pattern or spinner, " \
"got: #{pattern_or_spinner.class}"
"got: #{pattern_or_spinner.class}"
end
end

Expand Down Expand Up @@ -259,8 +264,8 @@ def error
# @api public
def on(key, &callback)
unless @callbacks.key?(key)
raise ArgumentError, "The event #{key} does not exist. " \
" Use :spin, :success, :error, or :done instead"
raise ArgumentError, "The event #{key} does not exist. " \
"Use :spin, :success, :error, or :done instead"
end
@callbacks[key] << callback
self
Expand Down Expand Up @@ -317,6 +322,8 @@ def spin_handler
# @api private
def success_handler
proc do
next if @manual_stop && @top_spinner

if success?
@top_spinner.success if @top_spinner
emit(:success)
Expand All @@ -329,6 +336,8 @@ def success_handler
# @api private
def error_handler
proc do
next if @manual_stop && @top_spinner

if error?
@top_spinner.error if @top_spinner
@fired ||= emit(:error) # fire once
Expand All @@ -341,6 +350,8 @@ def error_handler
# @api private
def done_handler
proc do
next if @manual_stop && @top_spinner

if done?
@top_spinner.stop if @top_spinner && !error? && !success?
emit(:done)
Expand Down
22 changes: 22 additions & 0 deletions spec/unit/multi/auto_spin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,27 @@
spinners.auto_spin

expect(jobs).to match_array(%w[one two])
expect(spinners.top_spinner.done?).to be(true)
end

context "when manual_stop option is set" do
it "keeps the top level spinner spinning" do
spinners = TTY::Spinner::Multi.new("top", output: output, manual_stop: true)
jobs = []

spinners.register("one") { |sp| jobs << "one"; sp.success }
spinners.register("two") { |sp| jobs << "two"; sp.success }

spinners.auto_spin

spinner = spinners.register("three") { |sp| jobs << "three"; sp.success }
spinner.run

expect(jobs).to match_array(%w[one two three])

expect(spinners.top_spinner.done?).to be(false)
spinners.success
expect(spinners.top_spinner.done?).to be(true)
end
end
end

0 comments on commit 5ff5412

Please sign in to comment.