From 5ff5412e7b64d8138596cc4ebde34c140abd2e78 Mon Sep 17 00:00:00 2001 From: Kev Date: Tue, 23 Jul 2024 01:25:28 +0200 Subject: [PATCH] Add manual_stop option --- README.md | 12 ++++++++++++ examples/multi/multi_manual_stop.rb | 25 +++++++++++++++++++++++++ lib/tty/spinner/multi.rb | 17 ++++++++++++++--- spec/unit/multi/auto_spin_spec.rb | 22 ++++++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 examples/multi/multi_manual_stop.rb diff --git a/README.md b/README.md index 288e8c7..5b54cfb 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/examples/multi/multi_manual_stop.rb b/examples/multi/multi_manual_stop.rb new file mode 100644 index 0000000..9e1dea2 --- /dev/null +++ b/examples/multi/multi_manual_stop.rb @@ -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 diff --git a/lib/tty/spinner/multi.rb b/lib/tty/spinner/multi.rb index 4f29c2c..2de01bf 100644 --- a/lib/tty/spinner/multi.rb +++ b/lib/tty/spinner/multi.rb @@ -49,6 +49,10 @@ 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) @@ -56,6 +60,7 @@ def initialize(*args) @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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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) diff --git a/spec/unit/multi/auto_spin_spec.rb b/spec/unit/multi/auto_spin_spec.rb index b724d14..fb31a8b 100644 --- a/spec/unit/multi/auto_spin_spec.rb +++ b/spec/unit/multi/auto_spin_spec.rb @@ -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