tty-spinner 0.8.0 → 0.9.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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +120 -0
  3. data/README.md +28 -10
  4. data/Rakefile +8 -0
  5. data/examples/auto_spin.rb +8 -0
  6. data/examples/basic.rb +8 -0
  7. data/examples/clear.rb +9 -0
  8. data/examples/color.rb +12 -0
  9. data/examples/error.rb +9 -0
  10. data/examples/formats.rb +11 -0
  11. data/examples/hide_cursor.rb +12 -0
  12. data/examples/multi/basic.rb +13 -0
  13. data/examples/multi/basic_top_level.rb +13 -0
  14. data/examples/multi/custom_style.rb +26 -0
  15. data/examples/multi/files.rb +14 -0
  16. data/examples/multi/jobs.rb +10 -0
  17. data/examples/multi/multi.rb +17 -0
  18. data/examples/multi/multi_top_level.rb +18 -0
  19. data/examples/multi/pause.rb +26 -0
  20. data/examples/multi/threaded.rb +30 -0
  21. data/examples/pause.rb +19 -0
  22. data/examples/run.rb +18 -0
  23. data/examples/success.rb +9 -0
  24. data/examples/threaded.rb +11 -0
  25. data/examples/update.rb +11 -0
  26. data/lib/tty-spinner.rb +0 -2
  27. data/lib/tty/spinner.rb +40 -30
  28. data/lib/tty/spinner/formats.rb +3 -3
  29. data/lib/tty/spinner/multi.rb +31 -12
  30. data/lib/tty/spinner/version.rb +2 -2
  31. data/spec/spec_helper.rb +51 -0
  32. data/spec/unit/auto_spin_spec.rb +27 -0
  33. data/spec/unit/clear_spec.rb +18 -0
  34. data/spec/unit/error_spec.rb +46 -0
  35. data/spec/unit/events_spec.rb +37 -0
  36. data/spec/unit/formats_spec.rb +9 -0
  37. data/spec/unit/frames_spec.rb +33 -0
  38. data/spec/unit/hide_cursor_spec.rb +53 -0
  39. data/spec/unit/job_spec.rb +14 -0
  40. data/spec/unit/join_spec.rb +12 -0
  41. data/spec/unit/multi/auto_spin_spec.rb +34 -0
  42. data/spec/unit/multi/error_spec.rb +109 -0
  43. data/spec/unit/multi/line_inset_spec.rb +59 -0
  44. data/spec/unit/multi/on_spec.rb +13 -0
  45. data/spec/unit/multi/register_spec.rb +47 -0
  46. data/spec/unit/multi/spin_spec.rb +103 -0
  47. data/spec/unit/multi/stop_spec.rb +97 -0
  48. data/spec/unit/multi/success_spec.rb +110 -0
  49. data/spec/unit/new_spec.rb +26 -0
  50. data/spec/unit/pause_spec.rb +25 -0
  51. data/spec/unit/reset_spec.rb +21 -0
  52. data/spec/unit/run_spec.rb +32 -0
  53. data/spec/unit/spin_spec.rb +90 -0
  54. data/spec/unit/stop_spec.rb +64 -0
  55. data/spec/unit/success_spec.rb +46 -0
  56. data/spec/unit/update_spec.rb +87 -0
  57. data/tasks/console.rake +11 -0
  58. data/tasks/coverage.rake +11 -0
  59. data/tasks/spec.rake +29 -0
  60. data/tty-spinner.gemspec +27 -0
  61. metadata +62 -9
@@ -0,0 +1,26 @@
1
+ require_relative '../../lib/tty-spinner'
2
+
3
+ spinners = TTY::Spinner::Multi.new("[:spinner]")
4
+
5
+ sp1 = spinners.register("[:spinner] one")
6
+ sp2 = spinners.register("[:spinner] two")
7
+ sp3 = spinners.register("[:spinner] three")
8
+
9
+ sp1.auto_spin
10
+ sp2.auto_spin
11
+ sp3.auto_spin
12
+
13
+ sleep(1)
14
+
15
+ spinners.pause
16
+
17
+ sleep(1)
18
+
19
+ spinners.resume
20
+
21
+ sleep(1)
22
+
23
+ sp1.stop
24
+ sp2.stop
25
+ sp3.stop
26
+ spinners.stop
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../lib/tty-spinner'
4
+
5
+ def spinner_options
6
+ [
7
+ ":spinner \e[1mNo\e[0m :number Row :line",
8
+ format: :dots,
9
+ error_mark: '✖',
10
+ success_mark: "\e[1m\e[32m✓\e[0m\e[0m"
11
+ ]
12
+ end
13
+
14
+ spinners = TTY::Spinner::Multi.new(*spinner_options)
15
+ threads = []
16
+
17
+ 20.times do |i|
18
+ threads << Thread.new do
19
+ spinner = spinners.register(*spinner_options)
20
+ sleep Random.rand(0.1..0.3)
21
+
22
+ 10.times do
23
+ sleep Random.rand(0.1..0.3)
24
+ spinner.update(number: "(#{i})", line: spinner.row)
25
+ spinner.spin
26
+ end
27
+ end
28
+ end
29
+
30
+ threads.each(&:join)
@@ -0,0 +1,19 @@
1
+ require_relative '../lib/tty-spinner'
2
+
3
+ spinner = TTY::Spinner.new("[:spinner] Task name")
4
+
5
+ spinner.auto_spin
6
+
7
+ sleep(2)
8
+
9
+ spinner.pause
10
+
11
+ sleep(2)
12
+
13
+ spinner.resume
14
+
15
+ sleep(2)
16
+
17
+ spinner.stop
18
+
19
+ puts
@@ -0,0 +1,18 @@
1
+ require_relative '../lib/tty-spinner'
2
+
3
+ # without block
4
+ spinner = TTY::Spinner.new(":title :spinner ...", format: :pulse_3)
5
+
6
+ def long_task
7
+ 10000000.times do |n|
8
+ n * n
9
+ end
10
+ end
11
+
12
+ spinner.update(title: 'Task 1')
13
+ spinner.run 'done' do
14
+ long_task
15
+ end
16
+
17
+ spinner.update(title: 'Task 2')
18
+ spinner.run('done') { long_task }
@@ -0,0 +1,9 @@
1
+ require_relative '../lib/tty-spinner'
2
+
3
+ spinner = TTY::Spinner.new("[:spinner] Task name")
4
+ 20.times do
5
+ spinner.spin
6
+ sleep(0.1)
7
+ end
8
+
9
+ spinner.success('(successful)')
@@ -0,0 +1,11 @@
1
+ require_relative '../lib/tty-spinner'
2
+
3
+ spinner = TTY::Spinner.new("[:spinner]")
4
+
5
+ th1 = Thread.new { 10.times { spinner.spin; sleep(0.1) } }
6
+ th2 = Thread.new { 10.times { spinner.spin; sleep(0.1) } }
7
+ th3 = Thread.new { 10.times { spinner.spin; sleep(0.1) } }
8
+
9
+ [th1, th2, th3].each(&:join)
10
+
11
+ spinner.success
@@ -0,0 +1,11 @@
1
+ require_relative '../lib/tty-spinner'
2
+
3
+ spinner = TTY::Spinner.new(":spinner :title", format: :pulse_3)
4
+
5
+ spinner.update(title: 'task aaaaa')
6
+
7
+ 20.times { spinner.spin; sleep(0.1) }
8
+
9
+ spinner.update(title: 'task b')
10
+
11
+ 20.times { spinner.spin; sleep(0.1) }
@@ -1,4 +1,2 @@
1
- # encoding: utf-8
2
-
3
1
  require_relative 'tty/spinner'
4
2
  require_relative 'tty/spinner/multi'
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'monitor'
@@ -18,11 +17,11 @@ module TTY
18
17
  # @raised when attempting to join dead thread
19
18
  NotSpinningError = Class.new(StandardError)
20
19
 
21
- ECMA_CSI = "\x1b[".freeze
20
+ ECMA_CSI = "\x1b["
22
21
 
23
22
  MATCHER = /:spinner/
24
- TICK = '✔'.freeze
25
- CROSS = '✖'.freeze
23
+ TICK = '✔'
24
+ CROSS = '✖'
26
25
 
27
26
  CURSOR_LOCK = Monitor.new
28
27
 
@@ -61,8 +60,16 @@ module TTY
61
60
  # @api public
62
61
  attr_reader :tokens
63
62
 
63
+ # The amount of time between frames in auto spinning
64
+ #
65
+ # @api public
64
66
  attr_reader :interval
65
67
 
68
+ # The current row inside the multi spinner
69
+ #
70
+ # @api public
71
+ attr_reader :row
72
+
66
73
  # Initialize a spinner
67
74
  #
68
75
  # @example
@@ -106,14 +113,23 @@ module TTY
106
113
 
107
114
  @callbacks = Hash.new { |h, k| h[k] = [] }
108
115
  @length = @frames.length
109
- @current = 0
110
- @done = false
111
- @state = :stopped
112
116
  @thread = nil
113
117
  @job = nil
114
118
  @multispinner= nil
115
- @succeeded = false
116
- @first_run = true
119
+ reset
120
+ end
121
+
122
+ # Reset the spinner to initial frame
123
+ #
124
+ # @api public
125
+ def reset
126
+ synchronize do
127
+ @current = 0
128
+ @done = false
129
+ @state = :stopped
130
+ @succeeded = false
131
+ @first_run = true
132
+ end
117
133
  end
118
134
 
119
135
  # Notifies the TTY::Spinner that it is running under a multispinner
@@ -202,13 +218,11 @@ module TTY
202
218
 
203
219
  # Execute this spinner job
204
220
  #
221
+ # @yield [TTY::Spinner]
222
+ #
205
223
  # @api public
206
224
  def execute_job
207
- if job.arity.zero?
208
- instance_eval(&job)
209
- else
210
- job.(self)
211
- end
225
+ job.(self) if job?
212
226
  end
213
227
 
214
228
  # Check if this spinner has a scheduled job
@@ -241,6 +255,10 @@ module TTY
241
255
  end
242
256
  end
243
257
  end
258
+ ensure
259
+ if @hide_cursor
260
+ write(TTY::Cursor.show, false)
261
+ end
244
262
  end
245
263
 
246
264
  # Checked if current spinner is paused
@@ -370,9 +388,6 @@ module TTY
370
388
  mon_enter
371
389
  return if done?
372
390
 
373
- if @hide_cursor
374
- write(TTY::Cursor.show, false)
375
- end
376
391
  clear_line
377
392
  return if @clear
378
393
 
@@ -388,6 +403,11 @@ module TTY
388
403
  @state = :stopped
389
404
  @done = true
390
405
  @started_at = nil
406
+
407
+ if @hide_cursor
408
+ write(TTY::Cursor.show, false)
409
+ end
410
+
391
411
  emit(:done)
392
412
  kill
393
413
  mon_exit
@@ -454,16 +474,6 @@ module TTY
454
474
  end
455
475
  end
456
476
 
457
- # Reset the spinner to initial frame
458
- #
459
- # @api public
460
- def reset
461
- synchronize do
462
- @current = 0
463
- @first_run = true
464
- end
465
- end
466
-
467
477
  private
468
478
 
469
479
  # Execute a block on the proper terminal line if the spinner is running
@@ -472,7 +482,7 @@ module TTY
472
482
  # @api private
473
483
  def execute_on_line
474
484
  if @multispinner
475
- CURSOR_LOCK.synchronize do
485
+ @multispinner.synchronize do
476
486
  if @first_run
477
487
  @row ||= @multispinner.next_row
478
488
  yield if block_given?
@@ -502,7 +512,7 @@ module TTY
502
512
  execute_on_line do
503
513
  output.print(TTY::Cursor.column(1)) if clear_first
504
514
  # If there's a top level spinner, print with inset
505
- characters_in = @multispinner.line_inset(self) if @multispinner
515
+ characters_in = @multispinner.line_inset(@row) if @multispinner
506
516
  output.print("#{characters_in}#{data}")
507
517
  output.flush
508
518
  end
@@ -553,7 +563,7 @@ module TTY
553
563
  def replace_tokens(string)
554
564
  data = string.dup
555
565
  @tokens.each do |name, val|
556
- data.gsub!(/\:#{name}/, val)
566
+ data.gsub!(/\:#{name}/, val.to_s)
557
567
  end
558
568
  data
559
569
  end
@@ -1,4 +1,4 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module TTY
4
4
  module Formats
@@ -21,7 +21,7 @@ module TTY
21
21
  },
22
22
  spin_4: {
23
23
  interval: 10,
24
- frames: %w{╫ ╪'}
24
+ frames: %w{╫ ╪}
25
25
  },
26
26
  pulse: {
27
27
  interval: 10,
@@ -164,7 +164,7 @@ module TTY
164
164
  },
165
165
  flip: {
166
166
  interval: 10,
167
- frames: '-◡⊙-◠'.freeze
167
+ frames: '-◡⊙-◠'
168
168
  },
169
169
  burger: {
170
170
  interval: 6,
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'monitor'
@@ -23,7 +22,7 @@ module TTY
23
22
  top: Gem.win_platform? ? '+ ' : "\u250c ",
24
23
  middle: Gem.win_platform? ? '|-- ' : "\u251c\u2500\u2500 ",
25
24
  bottom: Gem.win_platform? ? '|__ ' : "\u2514\u2500\u2500 "
26
- }.freeze
25
+ }
27
26
 
28
27
  # The current count of all rendered rows
29
28
  #
@@ -59,6 +58,7 @@ module TTY
59
58
  @inset_opts = @options.delete(:style) { DEFAULT_INSET }
60
59
  @rows = 0
61
60
  @spinners = []
61
+ @spinners_count = 0
62
62
  @top_spinner = nil
63
63
  @last_spin_at = nil
64
64
  unless message.nil?
@@ -75,19 +75,21 @@ module TTY
75
75
 
76
76
  # Register a new spinner
77
77
  #
78
- # @param [String] pattern
79
- # the pattern used for creating spinner
78
+ # @param [String, TTY::Spinner] pattern_or_spinner
79
+ # the pattern used for creating spinner, or a spinner instance
80
80
  #
81
81
  # @api public
82
- def register(pattern, options = {}, &job)
82
+ def register(pattern_or_spinner, **options, &job)
83
83
  observable = options.delete(:observable) { true }
84
- spinner = TTY::Spinner.new(pattern, @options.merge(options))
84
+ spinner = nil
85
85
 
86
86
  synchronize do
87
+ spinner = create_spinner(pattern_or_spinner, options)
87
88
  spinner.attach_to(self)
88
89
  spinner.job(&job) if block_given?
89
90
  observe(spinner) if observable
90
91
  @spinners << spinner
92
+ @spinners_count += 1
91
93
  if @top_spinner
92
94
  @spinners.each { |sp| sp.redraw_indent if sp.spinning? || sp.done? }
93
95
  end
@@ -96,6 +98,24 @@ module TTY
96
98
  spinner
97
99
  end
98
100
 
101
+ # Create a spinner instance
102
+ #
103
+ # @api private
104
+ def create_spinner(pattern_or_spinner, options)
105
+ case pattern_or_spinner
106
+ when ::String
107
+ TTY::Spinner.new(
108
+ pattern_or_spinner,
109
+ @options.merge(options)
110
+ )
111
+ when ::TTY::Spinner
112
+ pattern_or_spinner
113
+ else
114
+ raise ArgumentError, "Expected a pattern or spinner, " \
115
+ "got: #{pattern_or_spinner.class}"
116
+ end
117
+ end
118
+
99
119
  # Increase a row count
100
120
  #
101
121
  # @api public
@@ -161,20 +181,19 @@ module TTY
161
181
  # Find the number of characters to move into the line
162
182
  # before printing the spinner
163
183
  #
164
- # @param [TTY::Spinner] spinner
165
- # the spinner for which line inset is calculated
184
+ # @param [Integer] line_no
185
+ # the current spinner line number for which line inset is calculated
166
186
  #
167
187
  # @return [String]
168
188
  # the inset
169
189
  #
170
190
  # @api public
171
- def line_inset(spinner)
191
+ def line_inset(line_no)
172
192
  return '' if @top_spinner.nil?
173
193
 
174
- case spinner
175
- when @top_spinner
194
+ if line_no == 1
176
195
  @inset_opts[:top]
177
- when @spinners.last
196
+ elsif line_no == @spinners_count
178
197
  @inset_opts[:bottom]
179
198
  else
180
199
  @inset_opts[:middle]
@@ -1,7 +1,7 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module TTY
4
4
  class Spinner
5
- VERSION = '0.8.0'.freeze
5
+ VERSION = '0.9.0'
6
6
  end # Spinner
7
7
  end # TTY
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ if ENV['COVERAGE'] || ENV['TRAVIS']
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ Coveralls::SimpleCov::Formatter
10
+ ]
11
+
12
+ SimpleCov.start do
13
+ command_name 'spec'
14
+ add_filter 'spec'
15
+ end
16
+ end
17
+
18
+ require 'tty-spinner'
19
+
20
+ class StringIO
21
+ def tty?
22
+ true
23
+ end
24
+ end
25
+
26
+ RSpec.configure do |config|
27
+ config.expect_with :rspec do |expectations|
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ end
30
+
31
+ config.mock_with :rspec do |mocks|
32
+ mocks.verify_partial_doubles = true
33
+ end
34
+
35
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
36
+ config.disable_monkey_patching!
37
+
38
+ # This setting enables warnings. It's recommended, but in some cases may
39
+ # be too noisy due to issues in dependencies.
40
+ config.warnings = true
41
+
42
+ if config.files_to_run.one?
43
+ config.default_formatter = 'doc'
44
+ end
45
+
46
+ config.profile_examples = 2
47
+
48
+ config.order = :random
49
+
50
+ Kernel.srand config.seed
51
+ end