infobar 0.0.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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.utilsrc +26 -0
- data/Gemfile +5 -0
- data/README.md +38 -0
- data/Rakefile +28 -0
- data/TODO.md +22 -0
- data/VERSION +1 -0
- data/infobar.gemspec +52 -0
- data/lib/infobar.rb +139 -0
- data/lib/infobar/counter.rb +101 -0
- data/lib/infobar/display.rb +131 -0
- data/lib/infobar/duration.rb +15 -0
- data/lib/infobar/fancy_interface.rb +26 -0
- data/lib/infobar/frequency.rb +33 -0
- data/lib/infobar/input_output.rb +25 -0
- data/lib/infobar/message.rb +154 -0
- data/lib/infobar/number.rb +10 -0
- data/lib/infobar/spinner.rb +51 -0
- data/lib/infobar/timer.rb +47 -0
- data/lib/infobar/version.rb +8 -0
- data/spec/config/infobar.yml +20 -0
- data/spec/infobar/config_spec.rb +27 -0
- data/spec/infobar/counter_spec.rb +135 -0
- data/spec/infobar/display_spec.rb +71 -0
- data/spec/infobar/duration_spec.rb +12 -0
- data/spec/infobar/frequency_spec.rb +44 -0
- data/spec/infobar/input_output_spec.rb +34 -0
- data/spec/infobar/message_spec.rb +70 -0
- data/spec/infobar/number_spec.rb +12 -0
- data/spec/infobar/spinner_spec.rb +37 -0
- data/spec/infobar/timer_spec.rb +31 -0
- data/spec/infobar_spec.rb +148 -0
- data/spec/spec_helper.rb +12 -0
- metadata +210 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
class Infobar::Timer
|
2
|
+
def initialize
|
3
|
+
@n = 0
|
4
|
+
@x = 0.0
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :x
|
8
|
+
|
9
|
+
attr_reader :n
|
10
|
+
|
11
|
+
def add(time, count)
|
12
|
+
case @n
|
13
|
+
when 0
|
14
|
+
@n += 1
|
15
|
+
when 1
|
16
|
+
@n -= 1
|
17
|
+
duration = time - @time_last
|
18
|
+
self << (duration / @count_last)
|
19
|
+
self << (duration / count.to_f)
|
20
|
+
else
|
21
|
+
duration = time - @time_last
|
22
|
+
self << (duration / count.to_f)
|
23
|
+
end
|
24
|
+
@time_last, @count_last = time, count
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def rate
|
29
|
+
if @x.zero?
|
30
|
+
0.0
|
31
|
+
else
|
32
|
+
1.0 / @x
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def average_time
|
37
|
+
@x
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def <<(x)
|
43
|
+
@n +=1
|
44
|
+
@x += (x - @x) / @n
|
45
|
+
self
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
development:
|
3
|
+
label: Progress
|
4
|
+
message:
|
5
|
+
format: ' %l %c/%t (%P%%) in %te with %r, ETA %e @%E %s '
|
6
|
+
'%s':
|
7
|
+
frames: :braille7
|
8
|
+
message: ✓
|
9
|
+
'%r':
|
10
|
+
format: '%.2f %U/s'
|
11
|
+
unit: i
|
12
|
+
prefix: 1000
|
13
|
+
style:
|
14
|
+
done_fill: ░
|
15
|
+
done_fg_color: 22
|
16
|
+
done_bg_color: 40
|
17
|
+
todo_fill: ' '
|
18
|
+
todo_fg_color: 124
|
19
|
+
todo_bg_color: 214
|
20
|
+
show: <%= STDIN.tty? %>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Infobar config' do
|
4
|
+
before do
|
5
|
+
ComplexConfig::Provider.config_dir =
|
6
|
+
Pathname.new(__FILE__).dirname.dirname + 'config'
|
7
|
+
extend ComplexConfig::Provider::Shortcuts
|
8
|
+
ComplexConfig::Provider.reload
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
ComplexConfig::Provider.config_dir = nil
|
13
|
+
ComplexConfig::Provider.reload
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'configuration exists' do
|
17
|
+
expect(cc.infobar?).not_to be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'configures default infobar' do
|
21
|
+
Infobar(total: 23)
|
22
|
+
expect(infobar.display.output).to receive(:<<).with(?\r)
|
23
|
+
expect(infobar.display.output).to receive(:<<).with(%r(Progress 0/23.*⣽))
|
24
|
+
infobar.update
|
25
|
+
expect(infobar).to be_show
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Infobar::Counter do
|
4
|
+
let :counter do
|
5
|
+
described_class.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'can be initialized' do
|
9
|
+
expect(counter).to be_a described_class
|
10
|
+
expect(counter.current).to eq 0
|
11
|
+
expect(counter.total).to eq 0
|
12
|
+
expect(counter).not_to be_started
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can progress' do
|
16
|
+
expect(counter.progress).to eq counter
|
17
|
+
expect(counter).to be_started
|
18
|
+
expect(counter.current).to eq 1
|
19
|
+
expect(counter.total).to eq 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'can progress by arbitrary value' do
|
23
|
+
expect(counter.progress(by: 23)).to eq counter
|
24
|
+
expect(counter).to be_started
|
25
|
+
expect(counter.current).to eq 23
|
26
|
+
expect(counter.total).to eq 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'can be done' do
|
30
|
+
counter.reset(total: 3)
|
31
|
+
expect(counter).not_to be_done
|
32
|
+
expect(counter.progress(by: 2)).to eq counter
|
33
|
+
expect(counter).not_to be_done
|
34
|
+
expect(counter.progress).to eq counter
|
35
|
+
expect(counter).to be_done
|
36
|
+
expect(counter.progress(by: 23)).to eq counter
|
37
|
+
expect(counter).to be_done
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can be finished' do
|
41
|
+
counter.reset(total: 3)
|
42
|
+
expect(counter).not_to be_started
|
43
|
+
expect(counter).not_to be_finished
|
44
|
+
expect(counter.progress(by: 1)).to eq counter
|
45
|
+
expect(counter).to be_started
|
46
|
+
expect(counter).not_to be_finished
|
47
|
+
expect(counter.finish).to eq counter
|
48
|
+
expect(counter).to be_finished
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'can tell how far it has progressed' do
|
52
|
+
counter.reset(total: 3)
|
53
|
+
expect(counter.progressed).to be_zero
|
54
|
+
expect(counter.progress).to eq counter
|
55
|
+
expect(counter.progressed).to be_within(1e-3).of(1 / 3.0)
|
56
|
+
expect(counter.progress).to eq counter
|
57
|
+
expect(counter.progressed).to be_within(1e-3).of(2 / 3.0)
|
58
|
+
expect(counter.progress).to eq counter
|
59
|
+
expect(counter.progressed).to be_within(1e-3).of(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'cannot progress without knowing how far to go' do
|
63
|
+
expect(counter.progressed).to eq 0.0
|
64
|
+
expect(counter.progress).to eq counter
|
65
|
+
expect(counter.progressed).to eq 0.0
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'can tell how many counts we have' do
|
69
|
+
expect(counter.current).to be_zero
|
70
|
+
expect(counter.progress).to eq counter
|
71
|
+
expect(counter.current).to eq 1
|
72
|
+
expect(counter.progress).to eq counter
|
73
|
+
expect(counter.current).to eq 2
|
74
|
+
expect(counter.progress).to eq counter
|
75
|
+
expect(counter.current).to eq 3
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'can tell how far it still has to go' do
|
79
|
+
counter.reset(total: 3)
|
80
|
+
expect(counter.to_go).to eq 3
|
81
|
+
expect(counter.to_go?).to eq 3
|
82
|
+
expect(counter).to be_to_go
|
83
|
+
expect(counter.progress(by: 2)).to eq counter
|
84
|
+
expect(counter.to_go).to eq 1
|
85
|
+
expect(counter.to_go?).to eq 1
|
86
|
+
expect(counter).to be_to_go
|
87
|
+
expect(counter.progress).to eq counter
|
88
|
+
expect(counter.to_go).to be_zero
|
89
|
+
expect(counter.to_go?).to be_nil
|
90
|
+
expect(counter).not_to be_to_go
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'time_remaining' do
|
94
|
+
counter.reset(total: 3)
|
95
|
+
now = Time.now
|
96
|
+
Time.dummy(now - 2) { counter.progress }
|
97
|
+
Time.dummy(now - 1) { counter.progress }
|
98
|
+
expect(counter.time_remaining).to be_within(1e-3).of 1
|
99
|
+
counter.finish
|
100
|
+
expect(counter.time_remaining).to be_zero
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'time_elapsed' do
|
104
|
+
counter.reset(total: 3)
|
105
|
+
now = Time.now
|
106
|
+
expect(counter.time_elapsed).to be_within(1e-3).of 0
|
107
|
+
Time.dummy(now - 3) { counter.progress }
|
108
|
+
Time.dummy(now - 2) { counter.progress }
|
109
|
+
Time.dummy(now - 1) do
|
110
|
+
expect(counter.time_elapsed).to be_within(1e-3).of 2
|
111
|
+
end
|
112
|
+
counter.finish
|
113
|
+
expect(counter.time_elapsed).to be_within(1e-3).of 3
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'eta' do
|
117
|
+
counter.reset(total: 3)
|
118
|
+
now = Time.now
|
119
|
+
Time.dummy(now - 2) { counter.progress }
|
120
|
+
Time.dummy(now - 1) {
|
121
|
+
counter.progress
|
122
|
+
expect(counter.eta.to_i).to eq now.to_i
|
123
|
+
}
|
124
|
+
counter.finish
|
125
|
+
expect(counter.eta.to_i).to eq now.to_i
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'total_time' do
|
129
|
+
counter.reset(total: 3)
|
130
|
+
now = Time.now
|
131
|
+
Time.dummy(now - 2) { counter.progress }
|
132
|
+
Time.dummy(now - 1) { counter.progress }
|
133
|
+
expect(counter.total_time).to be_within(1e-3).of 3
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Infobar::Display do
|
4
|
+
let :output do
|
5
|
+
StringIO.new
|
6
|
+
end
|
7
|
+
|
8
|
+
let :display do
|
9
|
+
described_class.new
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
display.output = output
|
14
|
+
allow(display).to receive(:columns).and_return 40
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can be updated' do
|
18
|
+
display.update message: 'test', progressed: 0.5
|
19
|
+
expect(output.tap(&:rewind).read).to eq\
|
20
|
+
"\r\e[38;5;22m\e[48;5;40m░░░░░░░░░░░░░░░░░░te\e[0m\e[0m\e[38;5;40m\e[48;5;22mst \e[0m\e[0m"
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'update returns carriage first' do
|
24
|
+
expect(display).to receive(:carriage_return).and_call_original
|
25
|
+
display.update message: 'test', progressed: 0.5
|
26
|
+
expect(output.tap(&:rewind).read).to start_with ?\r
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'reset clears and sets to default style' do
|
30
|
+
expect(display).to receive(:clear).and_call_original
|
31
|
+
expect(display).to receive(:style=).with(display.class.default_style)
|
32
|
+
display.reset
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'has style' do
|
36
|
+
test_style = {
|
37
|
+
done_fill: ?X,
|
38
|
+
done_fg_color: 1,
|
39
|
+
done_bg_color: 9,
|
40
|
+
todo_fill: ?O,
|
41
|
+
todo_fg_color: 0,
|
42
|
+
todo_bg_color: 8
|
43
|
+
}
|
44
|
+
display.style = test_style
|
45
|
+
display.update message: 'test', progressed: 0.5
|
46
|
+
expect(output.tap(&:rewind).read).to eq\
|
47
|
+
"\r\e[38;5;1m\e[48;5;9mXXXXXXXXXXXXXXXXXXte\e[0m\e[0m\e[38;5;0m\e[48;5;8mstOOOOOOOOOOOOOOOOOO\e[0m\e[0m"
|
48
|
+
expect(display.style).to eq(test_style)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'can output newline' do
|
52
|
+
expect(display.output).to receive(:<<).with($/)
|
53
|
+
display.newline
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'can be shown' do
|
57
|
+
display.show = true
|
58
|
+
expect(display).to be_show
|
59
|
+
expect(output).to receive(:<<)
|
60
|
+
display.output << 'hello world'
|
61
|
+
expect(display.input).not_to be_nil
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'can be hidden' do
|
65
|
+
display.show = false
|
66
|
+
expect(display).not_to be_show
|
67
|
+
expect(output).not_to receive(:<<)
|
68
|
+
display.output << 'hello world'
|
69
|
+
expect(display.input).to be_nil
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Infobar::Duration do
|
4
|
+
it 'can convert duration into string' do
|
5
|
+
expect(described_class.new(3661).to_s).to eq '01:01:01'
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'can convert duration into string for format' do
|
9
|
+
expect(described_class.new(3661, format: '%h:%m').to_s).to eq '01:01'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Infobar::Frequency do
|
4
|
+
let :frequency do
|
5
|
+
described_class.new 1
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'can be updated' do
|
9
|
+
frequency.call {}
|
10
|
+
expect(frequency.instance_eval { @update }).to be_present
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can be called' do
|
14
|
+
called = false
|
15
|
+
frequency.call do
|
16
|
+
called = true
|
17
|
+
end
|
18
|
+
expect(called).to eq true
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'does not execute block if called too soon' do
|
22
|
+
Time.dummy(Time.now - 2) do
|
23
|
+
expect(frequency.called).to eq 0
|
24
|
+
frequency.call { }
|
25
|
+
expect(frequency.called).to eq 1
|
26
|
+
frequency.call { }
|
27
|
+
expect(frequency.called).to eq 1
|
28
|
+
end
|
29
|
+
frequency.call { }
|
30
|
+
expect(frequency.called).to eq 2
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'can be reset' do
|
34
|
+
expect(frequency.called).to eq 0
|
35
|
+
frequency.call { }
|
36
|
+
expect(frequency.called).to eq 1
|
37
|
+
frequency.reset
|
38
|
+
expect(frequency.called).to eq 0
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can be displayed' do
|
42
|
+
expect(frequency.to_s).to eq '1.0'
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Infobar::InputOutput do
|
4
|
+
around do |example|
|
5
|
+
infobar.display.output = Object.new
|
6
|
+
infobar.display.input = Object.new
|
7
|
+
example.run
|
8
|
+
infobar.display.output = $stdout
|
9
|
+
infobar.display.input = $stdin
|
10
|
+
infobar.reset
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can puts after clearing' do
|
14
|
+
expect(infobar.display).to receive(:clear)
|
15
|
+
expect(infobar.display.output).to receive(:puts)
|
16
|
+
infobar.puts 'hello'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can gets after clearing' do
|
20
|
+
expect(infobar.display).to receive(:clear)
|
21
|
+
expect(infobar.display.input).to receive(:gets)
|
22
|
+
infobar.gets
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can output newline' do
|
26
|
+
expect(infobar.display).to receive(:newline)
|
27
|
+
infobar.newline
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'can clear the infobar' do
|
31
|
+
expect(infobar.display).to receive(:clear)
|
32
|
+
infobar.clear
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Infobar::Message do
|
4
|
+
let :format do
|
5
|
+
'%c %t %T %l %p %q %P %Q %te %tt %e %E %r %a %s %%'
|
6
|
+
end
|
7
|
+
|
8
|
+
let :message do
|
9
|
+
described_class.new(format: format, '%p' => { format: '%.2f' })
|
10
|
+
end
|
11
|
+
|
12
|
+
let :now do
|
13
|
+
Time.parse('2011-11-11 11:11:11')
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
before do
|
18
|
+
Time.dummy(now - 3) do
|
19
|
+
Infobar.(current: 21, total: 42, label: 'Test')
|
20
|
+
end
|
21
|
+
Time.dummy(now - 2) do
|
22
|
+
+infobar
|
23
|
+
end
|
24
|
+
Time.dummy(now - 1) do
|
25
|
+
+infobar
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
infobar.reset
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'can be interpolated' do
|
34
|
+
Time.dummy(now) do
|
35
|
+
expect(message.to_str).to eq(
|
36
|
+
"23 42 19 Test 0.55 0.452 54.76 45.24 00:00:02 00:00:21 00:00:19 11:11:30 1.0 00:01.000000 – %"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can turn spinner into a message after finishing' do
|
42
|
+
Time.dummy(now) do
|
43
|
+
srand 1
|
44
|
+
message = described_class.new(
|
45
|
+
format: 'hello %s',
|
46
|
+
'%s' => {
|
47
|
+
random: true,
|
48
|
+
message: {
|
49
|
+
format: 'world at %E',
|
50
|
+
'%E' => { format: '%F %T' }
|
51
|
+
}
|
52
|
+
}
|
53
|
+
)
|
54
|
+
expect(message.to_str).to eq 'hello /'
|
55
|
+
infobar.finish
|
56
|
+
expect(message.to_str).to eq 'hello world at 2011-11-11 11:11:11'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'can be converted into a format string' do
|
61
|
+
expect(message.to_s).to eq format
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'can be converted into a hash' do
|
65
|
+
expect(message.to_hash).to eq(
|
66
|
+
format: format,
|
67
|
+
'%p' => { format: '%.2f' }
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|