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.
33 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 |
# File 'lib/powerbar.rb', line 33 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.
237 238 239 240 241 242 243 244 245 |
# File 'lib/powerbar.rb', line 237 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!
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/powerbar.rb', line 172 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
302 303 304 |
# File 'lib/powerbar.rb', line 302 def done state.done end |
#elapsed ⇒ Object
269 270 271 |
# File 'lib/powerbar.rb', line 269 def elapsed (state.time_now - state.time_start).to_f end |
#eta ⇒ Object
259 260 261 |
# File 'lib/powerbar.rb', line 259 def eta (state.total - state.done) / rate end |
#h_bar ⇒ Object
247 248 249 |
# File 'lib/powerbar.rb', line 247 def end |
#h_done ⇒ Object
306 307 308 |
# File 'lib/powerbar.rb', line 306 def h_done humanize_quantity(state.done) end |
#h_elapsed ⇒ Object
273 274 275 |
# File 'lib/powerbar.rb', line 273 def h_elapsed humanize_interval(elapsed) end |
#h_eta ⇒ Object
returns nil when eta is < 1 second
264 265 266 267 |
# File 'lib/powerbar.rb', line 264 def h_eta return nil unless scope.show_eta 1 < eta ? humanize_interval(eta) : nil end |
#h_msg ⇒ Object
255 256 257 |
# File 'lib/powerbar.rb', line 255 def h_msg msg end |
#h_percent ⇒ Object
282 283 284 |
# File 'lib/powerbar.rb', line 282 def h_percent sprintf "%d", percent end |
#h_rate ⇒ Object
290 291 292 |
# File 'lib/powerbar.rb', line 290 def h_rate humanize_quantity(round(rate, 1)) end |
#h_total ⇒ Object
298 299 300 |
# File 'lib/powerbar.rb', line 298 def h_total humanize_quantity(state.total) end |
#hook_exit ⇒ Object
Hook at_exit to ensure cleanup if we get interrupted
160 161 162 163 164 165 166 167 168 |
# File 'lib/powerbar.rb', line 160 def hook_exit return if @@exit_hooked if scope.template.exit at_exit do exit! end end @@exit_hooked = true end |
#msg ⇒ Object
251 252 253 |
# File 'lib/powerbar.rb', line 251 def msg state.msg end |
#percent ⇒ Object
277 278 279 280 |
# File 'lib/powerbar.rb', line 277 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
190 191 192 193 |
# File 'lib/powerbar.rb', line 190 def print(s) wipe scope.output.call(s) end |
#rate ⇒ Object
286 287 288 |
# File 'lib/powerbar.rb', line 286 def rate @rate.avg end |
#render(opts = {}) ⇒ Object
Render the PowerBar and return as a string.
224 225 226 227 |
# File 'lib/powerbar.rb', line 224 def render(opts={}) update(opts) render_template end |
#scope ⇒ Object
settings under current scope (e.g. tty.infinite)
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/powerbar.rb', line 139 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
134 135 136 |
# File 'lib/powerbar.rb', line 134 def settings @state.settings end |
#show(opts = {}, force = false) ⇒ Object
Output the PowerBar. Returns true if bar was shown, false otherwise.
209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/powerbar.rb', line 209 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
310 311 312 313 314 315 316 317 318 319 |
# File 'lib/powerbar.rb', line 310 def terminal_width if /solaris/ =~ RUBY_PLATFORM && (`stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/) w, r = [$2, $1] else w, r = `stty size 2>/dev/null`.split.reverse end w = `tput cols` unless w w = w.to_i if w w end |
#total ⇒ Object
294 295 296 |
# File 'lib/powerbar.rb', line 294 def total state.total end |
#update(opts = {}) ⇒ Object
Update state (and settings) without printing anything.
196 197 198 199 200 201 202 203 204 205 |
# File 'lib/powerbar.rb', line 196 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.
230 231 232 |
# File 'lib/powerbar.rb', line 230 def wipe scope.output.call(scope.template.wipe) end |