Class: PowerBar
- Inherits:
-
Object
- Object
- PowerBar
- Defined in:
- lib/powerbar.rb
Overview
This is PowerBar - The last progressbar-library you’ll ever need.
Defined Under Namespace
Classes: Rate
Constant Summary collapse
- STRIP_ANSI =
Regexp.compile '\e\[(\d+)(;\d+)?(;\d+)?[m|K]', nil
- RUBY18 =
RUBY_VERSION[0..2] == "1.8"
Instance Method Summary collapse
-
#bar ⇒ Object
Render the actual bar-portion of the PowerBar.
-
#close(fill = false) ⇒ Object
Print the close-template and defuse the exit-hook.
- #done ⇒ Object
- #elapsed ⇒ Object
- #eta ⇒ Object
- #h_bar ⇒ Object
- #h_done ⇒ Object
- #h_elapsed ⇒ Object
-
#h_eta ⇒ Object
returns nil when eta is < 1 second.
- #h_msg ⇒ Object
- #h_percent ⇒ Object
- #h_rate ⇒ Object
- #h_total ⇒ Object
-
#hook_exit ⇒ Object
Hook at_exit to ensure cleanup if we get interrupted.
-
#initialize(opts = {}) ⇒ PowerBar
constructor
A new instance of PowerBar.
- #msg ⇒ Object
- #percent ⇒ Object
-
#print(s) ⇒ Object
Remove progress-bar, print a message.
- #rate ⇒ Object
-
#render(opts = {}) ⇒ Object
Render the PowerBar and return as a string.
-
#scope ⇒ Object
settings under current scope (e.g. tty.infinite).
-
#settings ⇒ Object
settings-hash.
-
#show(opts = {}, force = false) ⇒ Object
Output the PowerBar.
- #terminal_width ⇒ Object
- #total ⇒ Object
-
#update(opts = {}) ⇒ Object
Update state (and settings) without printing anything.
-
#wipe ⇒ Object
Remove the PowerBar from the screen.
Constructor Details
#initialize(opts = {}) ⇒ PowerBar
Returns a new instance of PowerBar.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/powerbar.rb', line 34 def initialize(opts={}) @@exit_hooked = false @state = Hashie::Mash.new( { :time_last_show => Time.at(0), # <- don't mess with us :time_last_update => Time.at(0), # <- unless you know :time_start => nil, # <- what you're doing! :time_now => nil, # <- :msg => 'PowerBar!', :done => 0, :total => :unknown, :settings => { :rate_sample_max_interval => 10, # See PowerBar::Rate :rate_sample_window => 6, # See PowerBar::Rate :force_mode => nil, # set to :tty or :notty to force either mode :kilo => 1024, # Change this to 1000 when measuring network traffic or such. :tty => { # <== Settings when stdout is a tty :finite => { # <== Settings for a finite progress bar (when total != :unknown) # The :output Proc is called to draw on the screen --------------------. :output => Proc.new{ |s| $stderr.print s[0..terminal_width()-1] }, # <-' :interval => 0.1, # Minimum interval between screen refreshes (in seconds) :show_eta => true, # Set to false if you want to hide the ETA without changing the template :template => { # <== template for a finite progress bar on a tty :pre => "\e[1G\e[?25l", # printed before the progress-bar # # :main is the progressbar template # # The following tokens are available: # msg, bar, rate, percent, elapsed, eta, done, total # # Tokens may be used like so: # ${<foo>} # OR: # ${surrounding <foo> text} # # The surrounding text is only rendered when <foo> # evaluates to something other than nil. :main => '${<msg>}: ${[<bar>] }${<rate>/s }${<percent>% }${<elapsed>}${, ETA: <eta>}', :post => '', # printed after the progressbar :wipe => "\e[0m\e[1G\e[K", # printed when 'wipe' is called :close => "\e[?25h\n", # printed when 'close' is called :exit => "\e[?25h", # printed if the process exits unexpectedly :barchar => RUBY18 ? '#' : "\u2588", # fill-char for the progress-bar :padchar => RUBY18 ? '.' : "\u2022" # padding-char for the progress-bar }, }, :infinite => { # <== Settings for an infinite progress "bar" (when total is :unknown) :output => Proc.new{ |s| $stderr.print s[0..terminal_width()-1] }, :interval => 0.1, :show_eta => false, :template => { :pre => "\e[1G\e[?25l", :main => "${<msg>}: ${<done> }${<rate>/s }${<elapsed>}", :post => "\e[K", :wipe => "\e[0m\e[1G\e[K", :close => "\e[?25h\n", :exit => "\e[?25h", :barchar => RUBY18 ? '#' : "\u2588", :padchar => RUBY18 ? '.' : "\u2022" }, } }, :notty => { # <== Settings when stdout is not a tty :finite => { # You may want to hook in your favorite Logger-Library here. ---. :output => Proc.new{ |s| $stderr.print s }, # <----------------' :interval => 1, :show_eta => true, :line_width => 78, # Maximum output line width :template => { :pre => '', :main => "${<msg>}: ${<done>}/${<total>}, ${<percent>%}${, <rate>/s}${, elapsed: <elapsed>}${, ETA: <eta>}\n", :post => '', :wipe => '', :close => nil, :exit => nil, :barchar => "#", :padchar => "." }, }, :infinite => { :output => Proc.new{ |s| $stderr.print s }, :interval => 1, :show_eta => false, :line_width => 78, :template => { :pre => "", :main => "${<msg>}: ${<done> }${<rate>/s }${<elapsed>}\n", :post => "", :wipe => "", :close => nil, :exit => nil, :barchar => "#", :padchar => "." }, } } } }.merge(opts) ) end |
Instance Method Details
#bar ⇒ Object
Render the actual bar-portion of the PowerBar. The length of the bar is determined from the template. Returns nil if the bar-length would be == 0.
238 239 240 241 242 243 244 245 246 |
# File 'lib/powerbar.rb', line 238 def return nil if state.total.is_a? Symbol skel = render_template(:main, [:bar]) lwid = state.scope_at[0] == :tty ? terminal_width() : scope.line_width = [lwid - skel.gsub(STRIP_ANSI, '').length, 0].max fill = [0,[(state.done.to_f/state.total*).to_i,].min].max = scope.template. * fill + scope.template.padchar * [ - fill,0].max .length == 0 ? nil : end |
#close(fill = false) ⇒ Object
Print the close-template and defuse the exit-hook. Be a good citizen, always close your PowerBars!
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/powerbar.rb', line 173 def close(fill=false) show( { :done => fill && !state.total.is_a?(Symbol) ? state.total : state.done, :tty => { :finite => { :show_eta => false }, :infinite => { :show_eta => false }, }, :notty => { :finite => { :show_eta => false }, :infinite => { :show_eta => false }, }, }, true) scope.output.call(scope.template.close) unless scope.template.close.nil? state.closed = true end |
#done ⇒ Object
303 304 305 |
# File 'lib/powerbar.rb', line 303 def done state.done end |
#elapsed ⇒ Object
270 271 272 |
# File 'lib/powerbar.rb', line 270 def elapsed (state.time_now - state.time_start).to_f end |
#eta ⇒ Object
260 261 262 |
# File 'lib/powerbar.rb', line 260 def eta (state.total - state.done) / rate end |
#h_bar ⇒ Object
248 249 250 |
# File 'lib/powerbar.rb', line 248 def end |
#h_done ⇒ Object
307 308 309 |
# File 'lib/powerbar.rb', line 307 def h_done humanize_quantity(state.done) end |
#h_elapsed ⇒ Object
274 275 276 |
# File 'lib/powerbar.rb', line 274 def h_elapsed humanize_interval(elapsed) end |
#h_eta ⇒ Object
returns nil when eta is < 1 second
265 266 267 268 |
# File 'lib/powerbar.rb', line 265 def h_eta return nil unless scope.show_eta 1 < eta ? humanize_interval(eta) : nil end |
#h_msg ⇒ Object
256 257 258 |
# File 'lib/powerbar.rb', line 256 def h_msg msg end |
#h_percent ⇒ Object
283 284 285 |
# File 'lib/powerbar.rb', line 283 def h_percent sprintf "%d", percent end |
#h_rate ⇒ Object
291 292 293 |
# File 'lib/powerbar.rb', line 291 def h_rate humanize_quantity(round(rate, 1)) end |
#h_total ⇒ Object
299 300 301 |
# File 'lib/powerbar.rb', line 299 def h_total humanize_quantity(state.total) end |
#hook_exit ⇒ Object
Hook at_exit to ensure cleanup if we get interrupted
161 162 163 164 165 166 167 168 169 |
# File 'lib/powerbar.rb', line 161 def hook_exit return if @@exit_hooked if scope.template.exit at_exit do exit! end end @@exit_hooked = true end |
#msg ⇒ Object
252 253 254 |
# File 'lib/powerbar.rb', line 252 def msg state.msg end |
#percent ⇒ Object
278 279 280 281 |
# File 'lib/powerbar.rb', line 278 def percent return 0.0 if state.total.is_a? Symbol state.done.to_f/state.total*100 end |
#print(s) ⇒ Object
Remove progress-bar, print a message
191 192 193 194 |
# File 'lib/powerbar.rb', line 191 def print(s) wipe scope.output.call(s) end |
#rate ⇒ Object
287 288 289 |
# File 'lib/powerbar.rb', line 287 def rate @rate.avg end |
#render(opts = {}) ⇒ Object
Render the PowerBar and return as a string.
225 226 227 228 |
# File 'lib/powerbar.rb', line 225 def render(opts={}) update(opts) render_template end |
#scope ⇒ Object
settings under current scope (e.g. tty.infinite)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/powerbar.rb', line 140 def scope scope_hash = [settings.force_mode,state.total].hash return @state.scope unless @state.scope.nil? or scope_hash != @state.scope_hash state.scope_at = [ settings.force_mode || ($stdout.isatty ? :tty : :notty), :unknown == state.total ? :infinite : :finite ] state.scope = state.settings state.scope_at.each do |s| begin state.scope = state.scope[s] rescue NoMethodError raise StandardError, "Invalid configuration: #{state.scope_at.join('.')} "+ "(Can't resolve: #{state.scope_at[state.scope_at.index(s)-1]})" end end state.scope_hash = scope_hash state.scope end |
#settings ⇒ Object
settings-hash
135 136 137 |
# File 'lib/powerbar.rb', line 135 def settings @state.settings end |
#show(opts = {}, force = false) ⇒ Object
Output the PowerBar. Returns true if bar was shown, false otherwise.
210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/powerbar.rb', line 210 def show(opts={}, force=false) return false if scope.interval > Time.now - state.time_last_show and force == false update(opts) hook_exit state.time_last_show = Time.now state.closed = false scope.output.call(scope.template.pre) scope.output.call(render) scope.output.call(scope.template.post) true end |
#terminal_width ⇒ Object
311 312 313 314 315 |
# File 'lib/powerbar.rb', line 311 def terminal_width rows, cols = IO.console.winsize cols -= 1 if Gem.win_platform? cols end |
#total ⇒ Object
295 296 297 |
# File 'lib/powerbar.rb', line 295 def total state.total end |
#update(opts = {}) ⇒ Object
Update state (and settings) without printing anything.
197 198 199 200 201 202 203 204 205 206 |
# File 'lib/powerbar.rb', line 197 def update(opts={}) state.merge!(opts) state.time_start ||= Time.now state.time_now = Time.now @rate ||= PowerBar::Rate.new(state.time_now, state.settings.rate_sample_window, state.settings.rate_sample_max_interval) @rate.append(state.time_now, state.done) end |
#wipe ⇒ Object
Remove the PowerBar from the screen.
231 232 233 |
# File 'lib/powerbar.rb', line 231 def wipe scope.output.call(scope.template.wipe) end |