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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +120 -0
- data/README.md +28 -10
- data/Rakefile +8 -0
- data/examples/auto_spin.rb +8 -0
- data/examples/basic.rb +8 -0
- data/examples/clear.rb +9 -0
- data/examples/color.rb +12 -0
- data/examples/error.rb +9 -0
- data/examples/formats.rb +11 -0
- data/examples/hide_cursor.rb +12 -0
- data/examples/multi/basic.rb +13 -0
- data/examples/multi/basic_top_level.rb +13 -0
- data/examples/multi/custom_style.rb +26 -0
- data/examples/multi/files.rb +14 -0
- data/examples/multi/jobs.rb +10 -0
- data/examples/multi/multi.rb +17 -0
- data/examples/multi/multi_top_level.rb +18 -0
- data/examples/multi/pause.rb +26 -0
- data/examples/multi/threaded.rb +30 -0
- data/examples/pause.rb +19 -0
- data/examples/run.rb +18 -0
- data/examples/success.rb +9 -0
- data/examples/threaded.rb +11 -0
- data/examples/update.rb +11 -0
- data/lib/tty-spinner.rb +0 -2
- data/lib/tty/spinner.rb +40 -30
- data/lib/tty/spinner/formats.rb +3 -3
- data/lib/tty/spinner/multi.rb +31 -12
- data/lib/tty/spinner/version.rb +2 -2
- data/spec/spec_helper.rb +51 -0
- data/spec/unit/auto_spin_spec.rb +27 -0
- data/spec/unit/clear_spec.rb +18 -0
- data/spec/unit/error_spec.rb +46 -0
- data/spec/unit/events_spec.rb +37 -0
- data/spec/unit/formats_spec.rb +9 -0
- data/spec/unit/frames_spec.rb +33 -0
- data/spec/unit/hide_cursor_spec.rb +53 -0
- data/spec/unit/job_spec.rb +14 -0
- data/spec/unit/join_spec.rb +12 -0
- data/spec/unit/multi/auto_spin_spec.rb +34 -0
- data/spec/unit/multi/error_spec.rb +109 -0
- data/spec/unit/multi/line_inset_spec.rb +59 -0
- data/spec/unit/multi/on_spec.rb +13 -0
- data/spec/unit/multi/register_spec.rb +47 -0
- data/spec/unit/multi/spin_spec.rb +103 -0
- data/spec/unit/multi/stop_spec.rb +97 -0
- data/spec/unit/multi/success_spec.rb +110 -0
- data/spec/unit/new_spec.rb +26 -0
- data/spec/unit/pause_spec.rb +25 -0
- data/spec/unit/reset_spec.rb +21 -0
- data/spec/unit/run_spec.rb +32 -0
- data/spec/unit/spin_spec.rb +90 -0
- data/spec/unit/stop_spec.rb +64 -0
- data/spec/unit/success_spec.rb +46 -0
- data/spec/unit/update_spec.rb +87 -0
- data/tasks/console.rake +11 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- data/tty-spinner.gemspec +27 -0
- metadata +62 -9
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, '#auto_spin' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "starts and auto spins" do
|
7
|
+
spinner = TTY::Spinner.new(output: output, interval: 100)
|
8
|
+
allow(spinner).to receive(:spin)
|
9
|
+
|
10
|
+
spinner.auto_spin
|
11
|
+
sleep 0.1
|
12
|
+
spinner.stop
|
13
|
+
|
14
|
+
expect(spinner).to have_received(:spin).at_least(5).times
|
15
|
+
end
|
16
|
+
|
17
|
+
it "restores cursor when erorr is raised" do
|
18
|
+
spinner = TTY::Spinner.new(output: output, hide_cursor: true)
|
19
|
+
|
20
|
+
spinner.auto_spin {
|
21
|
+
raise 'boom'
|
22
|
+
}
|
23
|
+
|
24
|
+
output.rewind
|
25
|
+
expect(output.read).to start_with("\e[?25l").and end_with("\e[?25h")
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, ':clear' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "clears output when done" do
|
7
|
+
spinner = TTY::Spinner.new(clear: true, output: output)
|
8
|
+
3.times { spinner.spin }
|
9
|
+
spinner.stop('Done!')
|
10
|
+
output.rewind
|
11
|
+
expect(output.read).to eq([
|
12
|
+
"\e[1G|",
|
13
|
+
"\e[1G/",
|
14
|
+
"\e[1G-",
|
15
|
+
"\e[0m\e[2K\e[1G"
|
16
|
+
].join)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, '#error' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "marks spinner as error" do
|
7
|
+
spinner = TTY::Spinner.new(output: output)
|
8
|
+
3.times { spinner.spin }
|
9
|
+
spinner.error
|
10
|
+
output.rewind
|
11
|
+
expect(output.read).to eq([
|
12
|
+
"\e[1G|",
|
13
|
+
"\e[1G/",
|
14
|
+
"\e[1G-",
|
15
|
+
"\e[0m\e[2K",
|
16
|
+
"\e[1G#{TTY::Spinner::CROSS}\n"
|
17
|
+
].join)
|
18
|
+
|
19
|
+
expect(spinner.error?).to be(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "marks spinner as error with message" do
|
23
|
+
spinner = TTY::Spinner.new(output: output)
|
24
|
+
3.times { spinner.spin }
|
25
|
+
spinner.error('Error')
|
26
|
+
output.rewind
|
27
|
+
expect(output.read).to eq([
|
28
|
+
"\e[1G|",
|
29
|
+
"\e[1G/",
|
30
|
+
"\e[1G-",
|
31
|
+
"\e[0m\e[2K",
|
32
|
+
"\e[1G#{TTY::Spinner::CROSS} Error\n"
|
33
|
+
].join)
|
34
|
+
|
35
|
+
expect(spinner.error?).to be(true)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "changes error spinner marker" do
|
39
|
+
spinner = TTY::Spinner.new(error_mark: 'x', output: output)
|
40
|
+
spinner.error('(error)')
|
41
|
+
output.rewind
|
42
|
+
expect(output.read).to eq("\e[0m\e[2K\e[1Gx (error)\n")
|
43
|
+
|
44
|
+
expect(spinner.error?).to be(true)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, 'events' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "emits :done event" do
|
7
|
+
events = []
|
8
|
+
spinner = TTY::Spinner.new(output: output)
|
9
|
+
spinner.on(:done) { events << :done }
|
10
|
+
|
11
|
+
spinner.stop
|
12
|
+
|
13
|
+
expect(events).to eq([:done])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "emits :success event" do
|
17
|
+
events = []
|
18
|
+
spinner = TTY::Spinner.new(output: output)
|
19
|
+
spinner.on(:done) { events << :done }
|
20
|
+
spinner.on(:success) { events << :success }
|
21
|
+
|
22
|
+
spinner.success
|
23
|
+
|
24
|
+
expect(events).to match_array([:done, :success])
|
25
|
+
end
|
26
|
+
|
27
|
+
it "emits :error event" do
|
28
|
+
events = []
|
29
|
+
spinner = TTY::Spinner.new(output: output)
|
30
|
+
spinner.on(:done) { events << :done }
|
31
|
+
spinner.on(:error) { events << :error }
|
32
|
+
|
33
|
+
spinner.error
|
34
|
+
|
35
|
+
expect(events).to match_array([:done, :error])
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, ':frames' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "uses custom frames from string" do
|
7
|
+
frames = ".o0@*"
|
8
|
+
spinner = TTY::Spinner.new(frames: frames, output: output)
|
9
|
+
5.times { spinner.spin }
|
10
|
+
output.rewind
|
11
|
+
expect(output.read).to eq([
|
12
|
+
"\e[1G.",
|
13
|
+
"\e[1Go",
|
14
|
+
"\e[1G0",
|
15
|
+
"\e[1G@",
|
16
|
+
"\e[1G*"
|
17
|
+
].join)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "uses custom frames from array" do
|
21
|
+
frames = [".", "o", "0", "@", "*"]
|
22
|
+
spinner = TTY::Spinner.new(frames: frames, output: output)
|
23
|
+
5.times { spinner.spin }
|
24
|
+
output.rewind
|
25
|
+
expect(output.read).to eq([
|
26
|
+
"\e[1G.",
|
27
|
+
"\e[1Go",
|
28
|
+
"\e[1G0",
|
29
|
+
"\e[1G@",
|
30
|
+
"\e[1G*"
|
31
|
+
].join)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, ':hide_cursor' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "hides cursor" do
|
7
|
+
spinner = TTY::Spinner.new(output: output, hide_cursor: true)
|
8
|
+
4.times { spinner.spin }
|
9
|
+
spinner.stop
|
10
|
+
output.rewind
|
11
|
+
expect(output.read).to eq([
|
12
|
+
"\e[?25l\e[1G|",
|
13
|
+
"\e[1G/",
|
14
|
+
"\e[1G-",
|
15
|
+
"\e[1G\\",
|
16
|
+
"\e[0m\e[2K",
|
17
|
+
"\e[1G\\\n",
|
18
|
+
"\e[?25h"
|
19
|
+
].join)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "restores cursor on success" do
|
23
|
+
spinner = TTY::Spinner.new(output: output, hide_cursor: true)
|
24
|
+
4.times { spinner.spin }
|
25
|
+
spinner.success('success')
|
26
|
+
output.rewind
|
27
|
+
expect(output.read).to eq([
|
28
|
+
"\e[?25l\e[1G|",
|
29
|
+
"\e[1G/",
|
30
|
+
"\e[1G-",
|
31
|
+
"\e[1G\\",
|
32
|
+
"\e[0m\e[2K",
|
33
|
+
"\e[1G\u2714 success\n",
|
34
|
+
"\e[?25h"
|
35
|
+
].join)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "restores cursor on error" do
|
39
|
+
spinner = TTY::Spinner.new(output: output, hide_cursor: true)
|
40
|
+
4.times { spinner.spin }
|
41
|
+
spinner.error('error')
|
42
|
+
output.rewind
|
43
|
+
expect(output.read).to eq([
|
44
|
+
"\e[?25l\e[1G|",
|
45
|
+
"\e[1G/",
|
46
|
+
"\e[1G-",
|
47
|
+
"\e[1G\\",
|
48
|
+
"\e[0m\e[2K",
|
49
|
+
"\e[1G\u2716 error\n",
|
50
|
+
"\e[?25h"
|
51
|
+
].join)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, '#job' do
|
4
|
+
it "adds and executes job" do
|
5
|
+
spinner = TTY::Spinner.new("[:spinner] :title")
|
6
|
+
called = []
|
7
|
+
work = proc { |sp| called << sp }
|
8
|
+
spinner.job(&work)
|
9
|
+
|
10
|
+
spinner.execute_job
|
11
|
+
|
12
|
+
expect(called).to eq([spinner])
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner, '#join' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "raises exception when not spinning" do
|
7
|
+
spinner = TTY::Spinner.new(output: output)
|
8
|
+
expect {
|
9
|
+
spinner.join
|
10
|
+
}.to raise_error(TTY::Spinner::NotSpinningError)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner::Multi, '#auto_spin' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "doesn't auto spin top level spinner" do
|
7
|
+
spinners = TTY::Spinner::Multi.new("Top level spinner", output: output)
|
8
|
+
allow(spinners.top_spinner).to receive(:auto_spin)
|
9
|
+
|
10
|
+
spinners.auto_spin
|
11
|
+
|
12
|
+
expect(spinners.top_spinner).to_not have_received(:auto_spin)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "raises an exception when called without a top spinner" do
|
16
|
+
spinners = TTY::Spinner::Multi.new(output: output)
|
17
|
+
|
18
|
+
expect {
|
19
|
+
spinners.auto_spin
|
20
|
+
}.to raise_error(RuntimeError, /No top level spinner/)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "auto spins top level & child spinners with jobs" do
|
24
|
+
spinners = TTY::Spinner::Multi.new("top", output: output)
|
25
|
+
jobs = []
|
26
|
+
|
27
|
+
spinners.register("one") { |sp| jobs << 'one'; sp.success }
|
28
|
+
spinners.register("two") { |sp| jobs << 'two'; sp.success }
|
29
|
+
|
30
|
+
spinners.auto_spin
|
31
|
+
|
32
|
+
expect(jobs).to match_array(['one', 'two'])
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner::Multi, '#error' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it 'stops registerd multi spinner and emits an :error message' do
|
7
|
+
spinners = TTY::Spinner::Multi.new(":spinner", output: output)
|
8
|
+
callbacks = []
|
9
|
+
sp1 = spinners.register "[:spinner] one"
|
10
|
+
sp2 = spinners.register "[:spinner] two"
|
11
|
+
|
12
|
+
expect(sp1.error?).to eq(false)
|
13
|
+
expect(sp2.error?).to eq(false)
|
14
|
+
|
15
|
+
spinners.on(:error) { callbacks << :error }
|
16
|
+
.on(:done) { callbacks << :done }
|
17
|
+
.on(:success) { callbacks << :success }
|
18
|
+
|
19
|
+
spinners.error
|
20
|
+
|
21
|
+
expect(sp1.error?).to eq(true)
|
22
|
+
expect(sp2.error?).to eq(true)
|
23
|
+
expect(callbacks).to match_array([:done, :error])
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'stops unregistered top level spinner and emits an :error message' do
|
27
|
+
spinners = TTY::Spinner::Multi.new(output: output)
|
28
|
+
callbacks = []
|
29
|
+
sp1 = spinners.register "[:spinner] one"
|
30
|
+
sp2 = spinners.register "[:spinner] two"
|
31
|
+
|
32
|
+
expect(sp1.error?).to eq(false)
|
33
|
+
expect(sp2.error?).to eq(false)
|
34
|
+
|
35
|
+
spinners.on(:error) { callbacks << :error }
|
36
|
+
.on(:done) { callbacks << :done }
|
37
|
+
.on(:success) { callbacks << :success }
|
38
|
+
|
39
|
+
spinners.error
|
40
|
+
|
41
|
+
expect(sp1.error?).to eq(true)
|
42
|
+
expect(sp2.error?).to eq(true)
|
43
|
+
expect(callbacks).to match_array([:done, :error])
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'stops registed spinners under top level and emits an error message' do
|
47
|
+
spinners = TTY::Spinner::Multi.new(":spinner", output: output)
|
48
|
+
callbacks = []
|
49
|
+
sp1 = spinners.register "[:spinner] one"
|
50
|
+
sp2 = spinners.register "[:spinner] two"
|
51
|
+
|
52
|
+
expect(sp1.error?).to eq(false)
|
53
|
+
expect(sp2.error?).to eq(false)
|
54
|
+
|
55
|
+
spinners.on(:error) { callbacks << :error }
|
56
|
+
.on(:done) { callbacks << :done }
|
57
|
+
.on(:success) { callbacks << :success }
|
58
|
+
|
59
|
+
sp1.error
|
60
|
+
sp2.error
|
61
|
+
|
62
|
+
expect(spinners.error?).to eq(true)
|
63
|
+
expect(callbacks).to match_array([:done, :error])
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'stops registed spinners under top level and emits an error message' do
|
67
|
+
spinners = TTY::Spinner::Multi.new(output: output)
|
68
|
+
callbacks = []
|
69
|
+
sp1 = spinners.register "[:spinner] one"
|
70
|
+
sp2 = spinners.register "[:spinner] two"
|
71
|
+
|
72
|
+
expect(sp1.error?).to eq(false)
|
73
|
+
expect(sp2.error?).to eq(false)
|
74
|
+
|
75
|
+
spinners.on(:error) { callbacks << :error }
|
76
|
+
.on(:done) { callbacks << :done }
|
77
|
+
.on(:success) { callbacks << :success }
|
78
|
+
|
79
|
+
sp1.error
|
80
|
+
sp2.error
|
81
|
+
|
82
|
+
expect(spinners.error?).to eq(true)
|
83
|
+
expect(callbacks).to match_array([:done, :error])
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'returns true when any spinner failed' do
|
87
|
+
spinners = TTY::Spinner::Multi.new(output: output)
|
88
|
+
sp1 = spinners.register("one")
|
89
|
+
sp2 = spinners.register("two")
|
90
|
+
|
91
|
+
sp1.success
|
92
|
+
sp2.error
|
93
|
+
|
94
|
+
expect(spinners.error?).to eq(true)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "updates top spinner error state based on child spinners jobs failure" do
|
98
|
+
spinners = TTY::Spinner::Multi.new("top", output: output)
|
99
|
+
|
100
|
+
spinners.register("one") { |sp| sp.success }
|
101
|
+
spinners.register("two") { |sp| sp.error }
|
102
|
+
|
103
|
+
expect(spinners.error?).to eq(false)
|
104
|
+
|
105
|
+
spinners.auto_spin
|
106
|
+
|
107
|
+
expect(spinners.error?).to eq(true)
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
RSpec.describe TTY::Spinner::Multi, '#line_inset' do
|
4
|
+
let(:output) { StringIO.new('', 'w+') }
|
5
|
+
|
6
|
+
it "doesn't create inset when no top level spinner" do
|
7
|
+
spinners = TTY::Spinner::Multi.new(output: output)
|
8
|
+
|
9
|
+
spinner = spinners.register 'example'
|
10
|
+
|
11
|
+
expect(spinners.line_inset(spinner)).to eq('')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "defaults to the empty string for the top level spinner" do
|
15
|
+
spinners = TTY::Spinner::Multi.new("Top level spinner", output: output)
|
16
|
+
|
17
|
+
expect(spinners.line_inset(1))
|
18
|
+
.to eq(TTY::Spinner::Multi::DEFAULT_INSET[:top])
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns four spaces when there is a top level spinner" do
|
22
|
+
spinners = TTY::Spinner::Multi.new("Top level spinner", output: output)
|
23
|
+
|
24
|
+
spinners.register 'middle'
|
25
|
+
spinners.register 'bottom'
|
26
|
+
|
27
|
+
expect(spinners.line_inset(2))
|
28
|
+
.to eq(TTY::Spinner::Multi::DEFAULT_INSET[:middle])
|
29
|
+
end
|
30
|
+
|
31
|
+
it "decorates last spinner" do
|
32
|
+
spinners = TTY::Spinner::Multi.new("Top spinner", output: output)
|
33
|
+
|
34
|
+
spinners.register 'middle'
|
35
|
+
spinners.register 'bottom'
|
36
|
+
|
37
|
+
expect(spinners.line_inset(3))
|
38
|
+
.to eq(TTY::Spinner::Multi::DEFAULT_INSET[:bottom])
|
39
|
+
end
|
40
|
+
|
41
|
+
it "allows customization" do
|
42
|
+
opts = {
|
43
|
+
output: output,
|
44
|
+
indent: 4,
|
45
|
+
style: {
|
46
|
+
top: ". ",
|
47
|
+
middle: "--",
|
48
|
+
bottom: "---",
|
49
|
+
}
|
50
|
+
}
|
51
|
+
spinners = TTY::Spinner::Multi.new("Top level spinner", opts)
|
52
|
+
spinners.register ""
|
53
|
+
spinners.register ""
|
54
|
+
|
55
|
+
expect(spinners.line_inset(1)).to eq(". ")
|
56
|
+
expect(spinners.line_inset(2)).to eq("--")
|
57
|
+
expect(spinners.line_inset(3)).to eq("---")
|
58
|
+
end
|
59
|
+
end
|