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,131 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
require 'stringio'
|
3
|
+
require 'infobar/frequency'
|
4
|
+
|
5
|
+
class Infobar::Display
|
6
|
+
class << self
|
7
|
+
prepend Tins::Delegate
|
8
|
+
end
|
9
|
+
include Term::ANSIColor
|
10
|
+
|
11
|
+
def self.default_style
|
12
|
+
{
|
13
|
+
done_fill: ?░,
|
14
|
+
done_fg_color: 22,
|
15
|
+
done_bg_color: 40,
|
16
|
+
todo_fill: ' ',
|
17
|
+
todo_fg_color: 40,
|
18
|
+
todo_bg_color: 22,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
self.output = $stdout
|
24
|
+
self.input = $stdin
|
25
|
+
self.frequency = 0.05
|
26
|
+
@show = true
|
27
|
+
self.style = self.class.default_style
|
28
|
+
end
|
29
|
+
|
30
|
+
def frequency=(duration)
|
31
|
+
@frequency = Infobar::Frequency.new(duration)
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :frequency
|
35
|
+
|
36
|
+
attr_accessor :show
|
37
|
+
|
38
|
+
def show?
|
39
|
+
@show
|
40
|
+
end
|
41
|
+
|
42
|
+
def output=(io)
|
43
|
+
@output = io
|
44
|
+
@output.ask_and_send(:respond_to?, :sync=, true)
|
45
|
+
end
|
46
|
+
|
47
|
+
def output
|
48
|
+
if show?
|
49
|
+
@output
|
50
|
+
else
|
51
|
+
NULL
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_writer :input
|
56
|
+
|
57
|
+
def input
|
58
|
+
if show?
|
59
|
+
@input
|
60
|
+
else
|
61
|
+
NULL
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def style
|
66
|
+
self.class.default_style.each_key.each_with_object({}) do |attribute, h|
|
67
|
+
h[attribute] = instance_variable_get "@#{attribute}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def style=(new_style)
|
72
|
+
self.class.default_style.each_key do |attribute|
|
73
|
+
value = new_style[attribute]
|
74
|
+
value.nil? and next
|
75
|
+
instance_variable_set "@#{attribute}", value
|
76
|
+
end
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def update(message:, progressed:, force: false, **options)
|
81
|
+
force and @frequency.reset
|
82
|
+
@frequency.call do
|
83
|
+
message = Infobar.convert_to_message(message)
|
84
|
+
carriage_return
|
85
|
+
self.style = options
|
86
|
+
cols = columns
|
87
|
+
todo = message.to_str.center cols, replace_character
|
88
|
+
done = todo.slice!(0, (progressed * cols))
|
89
|
+
done.gsub!(replace_character, @done_fill[0])
|
90
|
+
todo.gsub!(replace_character, @todo_fill[0])
|
91
|
+
output << color(@done_fg_color, on_color(@done_bg_color, done)) +
|
92
|
+
color(@todo_fg_color, on_color(@todo_bg_color, todo))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
delegate :called, to: :frequency, as: :updates
|
97
|
+
|
98
|
+
def reset
|
99
|
+
clear
|
100
|
+
@frequency.reset
|
101
|
+
self.style = self.class.default_style
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
def clear
|
106
|
+
carriage_return
|
107
|
+
output << ' ' * columns
|
108
|
+
carriage_return
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def carriage_return
|
113
|
+
output << ?\r
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def newline
|
118
|
+
output << $/
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def replace_character
|
125
|
+
"\uFFFC"
|
126
|
+
end
|
127
|
+
|
128
|
+
def columns
|
129
|
+
Tins::Terminal.columns
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Infobar::FancyInterface
|
2
|
+
def ~
|
3
|
+
reset
|
4
|
+
end
|
5
|
+
|
6
|
+
def +@
|
7
|
+
progress by: 1
|
8
|
+
end
|
9
|
+
|
10
|
+
def +(by)
|
11
|
+
progress by: by
|
12
|
+
end
|
13
|
+
|
14
|
+
def coerce(other)
|
15
|
+
return self, other
|
16
|
+
end
|
17
|
+
|
18
|
+
def <<(item)
|
19
|
+
progress by: 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(*items)
|
23
|
+
progress by: items.size
|
24
|
+
end
|
25
|
+
alias push add
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Infobar::Frequency
|
2
|
+
def initialize(duration)
|
3
|
+
@duration = duration.to_f
|
4
|
+
@called = 0
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :duration
|
8
|
+
|
9
|
+
attr_reader :called
|
10
|
+
|
11
|
+
def update(now: Time.now)
|
12
|
+
@update = now
|
13
|
+
@called += 1
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(&block)
|
17
|
+
now = Time.now
|
18
|
+
if !@update || now - @update > @duration
|
19
|
+
update now: now
|
20
|
+
block.call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
@update = nil
|
26
|
+
@called = 0
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
@duration.to_s
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Infobar::InputOutput
|
2
|
+
def newline
|
3
|
+
@display.newline
|
4
|
+
self
|
5
|
+
end
|
6
|
+
|
7
|
+
def clear
|
8
|
+
@display.clear
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
%i[ print printf putc puts ].each do |method|
|
13
|
+
define_method(method) do |*a, &b|
|
14
|
+
@display.clear
|
15
|
+
@display.output.__send__(method, *a, &b)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
%i[ gets readline readlines ].each do |method|
|
20
|
+
define_method(method) do |*a, &b|
|
21
|
+
@display.clear
|
22
|
+
@display.input.__send__(method, *a, &b)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'infobar/spinner'
|
2
|
+
require 'infobar/duration'
|
3
|
+
require 'infobar/number'
|
4
|
+
|
5
|
+
class Infobar::Message
|
6
|
+
class << self
|
7
|
+
prepend Tins::Delegate
|
8
|
+
|
9
|
+
def register(directive, **opts, &block)
|
10
|
+
directives.key?(directive) and
|
11
|
+
warn "Overwriting old directive #{directive}."
|
12
|
+
directives[directive] = block
|
13
|
+
directive_default_options[directive] = opts
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def directives
|
18
|
+
@directives ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def directive_default_options
|
22
|
+
@directive_default_options ||= {}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# current counter value of items
|
27
|
+
register '%c' do
|
28
|
+
Infobar.counter.current
|
29
|
+
end
|
30
|
+
|
31
|
+
# total counter value of items
|
32
|
+
register '%t' do
|
33
|
+
Infobar.counter.total
|
34
|
+
end
|
35
|
+
|
36
|
+
# number of items to go
|
37
|
+
register '%T' do
|
38
|
+
Infobar.counter.to_go
|
39
|
+
end
|
40
|
+
|
41
|
+
# label of progress bar
|
42
|
+
register '%l' do
|
43
|
+
Infobar.label
|
44
|
+
end
|
45
|
+
|
46
|
+
# progressed so far as a float in 0..1
|
47
|
+
register('%p', format: '%.3f') do |directive, opts|
|
48
|
+
Infobar::Number.new(Infobar.counter.progressed, **opts)
|
49
|
+
end
|
50
|
+
|
51
|
+
# not yet progressed as a float in 0..1
|
52
|
+
register('%q', format: '%1.3f') do |directive, opts|
|
53
|
+
Infobar::Number.new(1 - Infobar.counter.progressed, **opts)
|
54
|
+
end
|
55
|
+
|
56
|
+
# progressed as a percentage float in 0..100
|
57
|
+
register('%P', format: '%3.2f') do |directive, opts|
|
58
|
+
Infobar::Number.new(100 * Infobar.counter.progressed, **opts)
|
59
|
+
end
|
60
|
+
|
61
|
+
# not yet progressed as a percentage float in 0..100
|
62
|
+
register('%Q', format: '%2.2f') do |directive, opts|
|
63
|
+
Infobar::Number.new(100 - 100 * Infobar.counter.progressed, **opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
# time elapsed as a duration
|
67
|
+
register('%te', format: '%h:%m:%s') do |directive, opts|
|
68
|
+
Infobar::Duration.new(Infobar.counter.time_elapsed, **opts)
|
69
|
+
end
|
70
|
+
|
71
|
+
# total time as a duration
|
72
|
+
register('%tt', format: '%h:%m:%s') do |directive, opts|
|
73
|
+
Infobar::Duration.new(Infobar.counter.total_time, **opts)
|
74
|
+
end
|
75
|
+
|
76
|
+
# ETA as a duration
|
77
|
+
register('%e', format: '%h:%m:%s') do |directive, opts|
|
78
|
+
Infobar::Duration.new(Infobar.counter.time_remaining, **opts)
|
79
|
+
end
|
80
|
+
|
81
|
+
# ETA as a datetime
|
82
|
+
register('%E', format: '%T') do |directive, opts|
|
83
|
+
if format = opts[:format]
|
84
|
+
Infobar.counter.eta.strftime(format)
|
85
|
+
else
|
86
|
+
Infobar.counter.eta
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# rate with or without units
|
91
|
+
register('%r', unit: nil, prefix: 1000, format: '%f %U') do |directive, opts|
|
92
|
+
if opts[:unit]
|
93
|
+
Tins::Unit.format(Infobar.counter.rate, **opts)
|
94
|
+
else
|
95
|
+
Infobar.counter.rate
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# average time as a duration
|
100
|
+
register('%a', format: '%m:%s.%f') do |directive, opts|
|
101
|
+
Infobar::Duration.new(Infobar.counter.average_time, **opts)
|
102
|
+
end
|
103
|
+
|
104
|
+
# spinner
|
105
|
+
register('%s', frames: :pipe, message: ?✓) do |directive, opts|
|
106
|
+
if Infobar.finished?
|
107
|
+
if message = opts[:message]
|
108
|
+
Infobar.convert_to_message(message).to_str
|
109
|
+
end
|
110
|
+
elsif opts[:random]
|
111
|
+
Infobar::Spinner.new(opts[:frames]).spin(:random)
|
112
|
+
else
|
113
|
+
Infobar::Spinner.new(opts[:frames]).spin(Infobar.display.updates)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# literal percentag character
|
118
|
+
register '%%' do
|
119
|
+
?%
|
120
|
+
end
|
121
|
+
|
122
|
+
def initialize(opts = {})
|
123
|
+
@format = opts.delete(:format) or
|
124
|
+
raise ArgumentError, 'format option required'
|
125
|
+
@opts = opts.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
|
126
|
+
end
|
127
|
+
|
128
|
+
attr_reader :opts
|
129
|
+
|
130
|
+
delegate :directives, to: self
|
131
|
+
|
132
|
+
delegate :directive_default_options, to: self
|
133
|
+
|
134
|
+
def opts_for(directive)
|
135
|
+
@opts.fetch(directive, directive_default_options[directive])
|
136
|
+
end
|
137
|
+
|
138
|
+
def to_str
|
139
|
+
keys = directives.keys.sort_by { |k| -k.size }
|
140
|
+
@format.gsub(/(?<!%)(#{keys * ?|})/) do
|
141
|
+
directives[$1].call($1, opts_for($1))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
attr_reader :format
|
146
|
+
|
147
|
+
alias to_s format
|
148
|
+
|
149
|
+
def to_hash
|
150
|
+
{
|
151
|
+
format: format,
|
152
|
+
}.merge(@opts)
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Infobar::Spinner
|
2
|
+
PREDEFINED = {
|
3
|
+
pipe: %w[ | / – \\ ],
|
4
|
+
arrow: %w[ ↑ ↗ → ↘ ↓ ↙ ← ↖ ],
|
5
|
+
bar1: %w[ ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ▇ ▆ ▅ ▄ ▃ ▂ ],
|
6
|
+
bar2: %w[ █ ▉ ▊ ▋ ▌ ▍ ▎ ▏ ▎ ▍ ▌ ▋ ▊ ▉ ],
|
7
|
+
braille7: %w[ ⣾ ⣽ ⣻ ⢿ ⡿ ⣟ ⣯ ⣷ ],
|
8
|
+
braille1: %w[ ⠁ ⠂ ⠄ ⡀ ⢀ ⠠ ⠐ ⠈ ],
|
9
|
+
square1: %w[ ▖ ▘ ▝ ▗ ],
|
10
|
+
square2: %w[ ◰ ◳ ◲ ◱ ],
|
11
|
+
tetris: %w[ ▌ ▀ ▐▄ ],
|
12
|
+
eyes: %w[ ◡◡ ⊙⊙ ◠◠ ],
|
13
|
+
corners: %w[ ┤ ┘ ┴ └ ├ ┌ ┬ ┐ ],
|
14
|
+
triangle: %w[ ◢ ◣ ◤ ◥ ],
|
15
|
+
circle1: %w[ ◴ ◷ ◶ ◵ ],
|
16
|
+
circle2: %w[ ◐ ◓ ◑ ◒ ],
|
17
|
+
circle3: %w[ ◜ ◝ ◞ ◟ ],
|
18
|
+
cross: %w[ + × ],
|
19
|
+
cylon: [ '● ', ' ● ', ' ●', ' ● ' ],
|
20
|
+
pacman: [ 'ᗧ∙∙∙∙●', ' O∙∙∙●', ' ᗧ∙∙●',' O∙●', ' ᗧ●', 'ᗣ O', ' ᗣ ᗤ', ' ᗣ O ', ' ᗣ ᗤ ', ' ᗣO ', ' ᗤ ', 'O ∞ ', 'ᗧ ∞ ', 'O ' ],
|
21
|
+
asteroids: [ 'ᐊ ◍', 'ᐃ ◍', 'ᐓ ◍', 'ᐅ· ◍', 'ᐅ ·◍', 'ᐅ ○', 'ᐅ ◌', 'ᐁ ' ],
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(frames = nil)
|
25
|
+
@frames =
|
26
|
+
case frames
|
27
|
+
when Array
|
28
|
+
frames
|
29
|
+
when Symbol
|
30
|
+
PREDEFINED.fetch(frames) do
|
31
|
+
|k| raise KeyError, "frames #{k} not predefined"
|
32
|
+
end
|
33
|
+
when nil
|
34
|
+
PREDEFINED[:pipe]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def spin(count)
|
39
|
+
@string =
|
40
|
+
if count == :random
|
41
|
+
@frames[rand(@frames.size)]
|
42
|
+
else
|
43
|
+
@frames[count % @frames.size]
|
44
|
+
end
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
@string
|
50
|
+
end
|
51
|
+
end
|