Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add manual_stop option #53

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [82/80]

jobs = []

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/Semicolon: Do not use semicolons to terminate expressions.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/Semicolon: Do not use semicolons to terminate expressions.


spinners.auto_spin

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/Semicolon: Do not use semicolons to terminate expressions.

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