From 322a07ffc9177e92da17da5565ba8d0c795fe4b9 Mon Sep 17 00:00:00 2001 From: jfelchner Date: Mon, 11 Apr 2011 16:35:34 -0500 Subject: [PATCH] Base refactoring work laid out --- lib/progress_bar.rb | 6 + lib/progress_bar/base.rb | 176 +++++++++++++++++++ lib/progress_bar/components.rb | 2 + lib/progress_bar/components/bar.rb | 63 +++++++ lib/progress_bar/components/title.rb | 27 +++ lib/progress_bar/format.rb | 2 + lib/progress_bar/format/base.rb | 41 +++++ lib/progress_bar/format/molecule.rb | 36 ++++ lib/progress_bar/formatter.rb | 29 ++++ lib/progress_bar/length_calculator.rb | 55 ++++++ lib/progress_bar/options_parser.rb | 13 ++ lib/progress_bar/version.rb | 3 + lib/progressbar.rb | 237 -------------------------- spec/progress_bar/bar_spec.rb | 148 ++++++++++++++++ spec/progress_bar/base_spec.rb | 147 ++++++++++++++++ 15 files changed, 748 insertions(+), 237 deletions(-) create mode 100644 lib/progress_bar.rb create mode 100644 lib/progress_bar/base.rb create mode 100644 lib/progress_bar/components.rb create mode 100644 lib/progress_bar/components/bar.rb create mode 100644 lib/progress_bar/components/title.rb create mode 100644 lib/progress_bar/format.rb create mode 100644 lib/progress_bar/format/base.rb create mode 100644 lib/progress_bar/format/molecule.rb create mode 100644 lib/progress_bar/formatter.rb create mode 100644 lib/progress_bar/length_calculator.rb create mode 100644 lib/progress_bar/options_parser.rb create mode 100644 lib/progress_bar/version.rb delete mode 100644 lib/progressbar.rb create mode 100644 spec/progress_bar/bar_spec.rb create mode 100644 spec/progress_bar/base_spec.rb diff --git a/lib/progress_bar.rb b/lib/progress_bar.rb new file mode 100644 index 00000000..654a2b50 --- /dev/null +++ b/lib/progress_bar.rb @@ -0,0 +1,6 @@ +require File.join(File.dirname(__FILE__), "progress_bar", "options_parser") +require File.join(File.dirname(__FILE__), "progress_bar", "length_calculator") +require File.join(File.dirname(__FILE__), "progress_bar", "formatter") +require File.join(File.dirname(__FILE__), "progress_bar", "components") +require File.join(File.dirname(__FILE__), "progress_bar", "format") +require File.join(File.dirname(__FILE__), "progress_bar", "base") diff --git a/lib/progress_bar/base.rb b/lib/progress_bar/base.rb new file mode 100644 index 00000000..1504127b --- /dev/null +++ b/lib/progress_bar/base.rb @@ -0,0 +1,176 @@ +# +# Ruby/ProgressBar - a text progress bar library +# +# Copyright (C) 2001-2005 Satoru Takabayashi +# All rights reserved. +# This is free software with ABSOLUTELY NO WARRANTY. +# +# You can redistribute it and/or modify it under the terms +# of Ruby's license. +# + +module ProgressBar + class Base + include ProgressBar::OptionsParser + include ProgressBar::LengthCalculator + include ProgressBar::Formatter + + DEFAULT_OUTPUT_STREAM = STDERR + DEFAULT_BAR_FORMAT = '%t: |%b|' + + def initialize(options = {}) + @out = options[:output_stream] || DEFAULT_OUTPUT_STREAM + + @length_override = ENV['RUBY_PROGRESS_BAR_LENGTH'] || options[:length] + + @format = options[:format] || DEFAULT_BAR_FORMAT + + @title = ProgressBar::Title.new(title_options_from(options)) + @bar = ProgressBar::Bar.new(bar_options_from(options)) + # @estimated_time = ProgressBar::EstimatedTime + # @elapsed_time = ProgressBar::ElapsedTime + end + + def clear + @out.print clear_string + end + + def start(options = {}) + clear + + @bar.current = options[:at] || @bar.current + # @estimated_time.start + # @elapsed_time.start + + update + end + + def inc + puts "#inc is deprecated. Please use #increment" + increment + end + + def increment + @bar.increment + # @previous_time = Time.now + update + end + + def title + @title.to_s + end + + def to_s(format_string = nil) + format_string ||= @format + + format(format_string) + end + + private + attr_reader :out + + def bar(length) + @bar.to_s(length) + end + + def clear_string + "\r#{" " * length}\r" + end + + def update + # return if finished? + + if length_changed? + clear + reset_length + end + + @out.print self.to_s + "\r" + @out.flush + end + + # def reset + # end + + # def inc(step = 1) + # set(@current + step) + # end + + # def set(progress) + # unless progress_range.include? progress + # raise "#{progress} is an invalid number. It must be between 0 and #{@total}." + # end + + # @previous = @current + # @current = progress + # update + # end + + # def finish + # @current = @total + # update + # end + + # def halt + # stop + # end + + # def stop + # update + # end + + # def pause + # update + # end + + # def finished? + # @current == @total + # end + + # def percentage + # progress_as_percentage(@current) + # end + + # def inspect + # "#" + # end + + # private + # def text + # arguments = @format_arguments.map do |method| + # method = sprintf("fmt_%s", method) + # send(method) + # end + + # sprintf(@format, *arguments) + eol + # "PROGRESS BAR!!#{eol}" + # end + + # def eol + # if finished? then "\n" else "\r" end + # end + + # def percentage_changed? + # Use "!=" instead of ">" to support negative changes + # current_percentage != previous_percentage + # end + + # def time_elapsed? + # Time.now - @previous_time >= 1 + # end + + # alias :current_percentage, :percentage + + # def previous_percentage + # progress_as_percentage(@previous) + # end + + # def progress_as_percentage(progress) + # (progress * 100 / @total).to_i + # end + + # def progress_range + # 0..@total + # end + end +end diff --git a/lib/progress_bar/components.rb b/lib/progress_bar/components.rb new file mode 100644 index 00000000..d61866a2 --- /dev/null +++ b/lib/progress_bar/components.rb @@ -0,0 +1,2 @@ +require File.join(File.dirname(__FILE__), "components", "bar") +require File.join(File.dirname(__FILE__), "components", "title") diff --git a/lib/progress_bar/components/bar.rb b/lib/progress_bar/components/bar.rb new file mode 100644 index 00000000..7304accf --- /dev/null +++ b/lib/progress_bar/components/bar.rb @@ -0,0 +1,63 @@ +module ProgressBar + class Bar + OPTIONS = [:total, :progress_mark, :beginning_position] + + DEFAULT_TOTAL = 100 + DEFAULT_BEGINNING_POSITION = 0 + DEFAULT_PROGRESS_MARK = 'o' + + #TODO These could be private right now. + attr_reader :total + attr_reader :current + attr_reader :progress_mark + + def initialize(options = {}) + @total = options[:total] || DEFAULT_TOTAL + @current = options[:beginning_position] || DEFAULT_BEGINNING_POSITION + + raise "You can't set the bar's current value to be greater than the total." if current > total + + @progress_mark = options[:progress_mark] || DEFAULT_PROGRESS_MARK + end + + def increment + @current += 1 unless current == total + end + + #TODO needs tested + def current=(new_current) + raise "You can't set the bar's current value to be greater than the total." if new_current > total + + @current = new_current + end + + def percentage_completed + # current / total * 100 + # + # Doing this way so we can avoid converting each + # number to a float and then back to an integer. + # + current * 100 / total + end + + def to_s(length) + @length = length + "#{complete_string}#{empty_string}" + end + + private + attr_reader :length + + def complete_string + @progress_mark * completed_length + end + + def completed_length + length * percentage_completed / 100 + end + + def empty_string + " " * (length - completed_length) + end + end +end diff --git a/lib/progress_bar/components/title.rb b/lib/progress_bar/components/title.rb new file mode 100644 index 00000000..6f6ef877 --- /dev/null +++ b/lib/progress_bar/components/title.rb @@ -0,0 +1,27 @@ +module ProgressBar + class Title + OPTIONS = [:title, :title_length] + + DEFAULT_TITLE = 'Progress' + + attr_reader :text + + def initialize(options = {}) + @text = options[:title] || DEFAULT_TITLE + @length_override = options[:title_length] + end + + def to_s + text + end + + # private + # def visible_text + # text.slice(0, visible_text_length) + # end + + # def visible_text_length + # @length_override || text.length + # end + end +end diff --git a/lib/progress_bar/format.rb b/lib/progress_bar/format.rb new file mode 100644 index 00000000..26b15f66 --- /dev/null +++ b/lib/progress_bar/format.rb @@ -0,0 +1,2 @@ +require File.join(File.dirname(__FILE__), "format", "molecule") +require File.join(File.dirname(__FILE__), "format", "base") diff --git a/lib/progress_bar/format/base.rb b/lib/progress_bar/format/base.rb new file mode 100644 index 00000000..41a3fe81 --- /dev/null +++ b/lib/progress_bar/format/base.rb @@ -0,0 +1,41 @@ +module ProgressBar + module Format + class Base + attr_reader :molecules + + def initialize(format_string) + @molecules = parse(format_string) + end + + def non_bar_molecules + molecules.select { |molecule| !molecule.bar_molecule? } + end + + def bar_molecules + molecules.select { |molecule| molecule.bar_molecule? } + end + + private + def parse(format_string) + molecules = [] + + format_string.scan(/%([tTb])/) do |match| + molecules << Molecule.new(match[0]) + end + + molecules + end + + # @title_width = 14 + # @format = "%-#{@title_width}s %3d%% %s %s" + # @format_arguments = [:title, :percentage, :bar, :stat] + + # def format=(format) + # @format = format + # end + + # def format_arguments=(arguments) + # @format_arguments = arguments + end + end +end diff --git a/lib/progress_bar/format/molecule.rb b/lib/progress_bar/format/molecule.rb new file mode 100644 index 00000000..47dd216c --- /dev/null +++ b/lib/progress_bar/format/molecule.rb @@ -0,0 +1,36 @@ +module ProgressBar + module Format + class Molecule + MOLECULES = { + :t => [:left_justified_title, :title], + :T => [:right_justified_title, :title], + :b => [:bar, :bar] + # :elapsed_time => "%a", + # :estimated_time_with_unknown => "%e", + # :estimated_time_with_greater_than => "%E", + # :force_estimated_time => "%f", + # :percentage_complete_as_integer => "%p", + # :percentage_complete_as_float => "%P", + # :current_capacity => "%c", + # :total_capacity => "%C", + # :bar_with_percentage => "%B", + # :reversed_bar => "%r", + # :reversed_bar_with_percentage => "%R" + } + + BAR_MOLECULES = %w{b} + + attr_reader :key + attr_reader :method_name + + def initialize(letter) + @key = letter + @description, @method_name = MOLECULES[@key.to_sym] + end + + def bar_molecule? + BAR_MOLECULES.include? @key + end + end + end +end diff --git a/lib/progress_bar/formatter.rb b/lib/progress_bar/formatter.rb new file mode 100644 index 00000000..b23077ca --- /dev/null +++ b/lib/progress_bar/formatter.rb @@ -0,0 +1,29 @@ +module ProgressBar + module Formatter + def format(format_string) + @format_string = format_string + @format = ProgressBar::Format::Base.new(format_string) + process + end + + def process + processed_string = @format_string.dup + + @format.non_bar_molecules.each do |molecule| + processed_string.gsub!("%#{molecule.key}", self.send(molecule.method_name)) + end + + remaining_molecule_match_data = processed_string.match(/%[^%]/) + remaining_molecules = remaining_molecule_match_data ? remaining_molecule_match_data.size : 0 + placeholder_length = remaining_molecules * 2 + + leftover_bar_length = length - processed_string.length + placeholder_length + + @format.bar_molecules.each do |molecule| + processed_string.gsub!("%#{molecule.key}", self.send(molecule.method_name, leftover_bar_length / remaining_molecules)) + end + + processed_string + end + end +end diff --git a/lib/progress_bar/length_calculator.rb b/lib/progress_bar/length_calculator.rb new file mode 100644 index 00000000..630a43a5 --- /dev/null +++ b/lib/progress_bar/length_calculator.rb @@ -0,0 +1,55 @@ +module ProgressBar + module LengthCalculator + private + def bar_length + length - title_length + end + + def title_length + @title.to_s.length + end + + def length + @current_length || calculate_length + end + + def length_changed? + @current_length == calculate_length + end + + def calculate_length + @length_override || terminal_width || 80 + end + + def reset_length + @current_length = calculate_length + end + + # This code was copied and modified from Rake, available under MIT-LICENSE + # Copyright (c) 2003, 2004 Jim Weirich + def terminal_width + return 80 unless unix? + + result = dynamic_width + (result < 20) ? 80 : result + rescue + 80 + end + + def dynamic_width + dynamic_width_stty.nonzero? || dynamic_width_tput + end + + def dynamic_width_stty + %x{stty size 2>/dev/null}.split[1].to_i + end + + def dynamic_width_tput + %x{tput cols 2>/dev/null}.to_i + end + + def unix? + RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i + end + end +end diff --git a/lib/progress_bar/options_parser.rb b/lib/progress_bar/options_parser.rb new file mode 100644 index 00000000..91196dda --- /dev/null +++ b/lib/progress_bar/options_parser.rb @@ -0,0 +1,13 @@ +module ProgressBar + module OptionsParser + private + def title_options_from(options) + options.select {|k,v| ProgressBar::Title::OPTIONS.include? k} + end + + def bar_options_from(options) + options[:length] = bar_length + options.select {|k,v| ProgressBar::Bar::OPTIONS.include? k} + end + end +end diff --git a/lib/progress_bar/version.rb b/lib/progress_bar/version.rb new file mode 100644 index 00000000..8502c27e --- /dev/null +++ b/lib/progress_bar/version.rb @@ -0,0 +1,3 @@ +module ProgressBar + VERSION = "0.9.0" +end diff --git a/lib/progressbar.rb b/lib/progressbar.rb deleted file mode 100644 index 019ca6b7..00000000 --- a/lib/progressbar.rb +++ /dev/null @@ -1,237 +0,0 @@ -# -# Ruby/ProgressBar - a text progress bar library -# -# Copyright (C) 2001-2005 Satoru Takabayashi -# All rights reserved. -# This is free software with ABSOLUTELY NO WARRANTY. -# -# You can redistribute it and/or modify it under the terms -# of Ruby's license. -# - -class ProgressBar - VERSION = "0.9" - - def initialize (title, total, out = STDERR) - @title = title - @total = total - @out = out - @terminal_width = 80 - @bar_mark = "o" - @current = 0 - @previous = 0 - @finished_p = false - @start_time = Time.now - @previous_time = @start_time - @title_width = 14 - @format = "%-#{@title_width}s %3d%% %s %s" - @format_arguments = [:title, :percentage, :bar, :stat] - clear - show - end - attr_reader :title - attr_reader :current - attr_reader :total - attr_accessor :start_time - attr_writer :bar_mark - - private - def fmt_bar - bar_width = do_percentage * @terminal_width / 100 - sprintf("|%s%s|", - @bar_mark * bar_width, - " " * (@terminal_width - bar_width)) - end - - def fmt_percentage - do_percentage - end - - def fmt_stat - if @finished_p then elapsed else eta end - end - - def fmt_stat_for_file_transfer - if @finished_p then - sprintf("%s %s %s", bytes, transfer_rate, elapsed) - else - sprintf("%s %s %s", bytes, transfer_rate, eta) - end - end - - def fmt_title - @title[0,(@title_width - 1)] + ":" - end - - def convert_bytes (bytes) - if bytes < 1024 - sprintf("%6dB", bytes) - elsif bytes < 1024 * 1000 # 1000kb - sprintf("%5.1fKB", bytes.to_f / 1024) - elsif bytes < 1024 * 1024 * 1000 # 1000mb - sprintf("%5.1fMB", bytes.to_f / 1024 / 1024) - else - sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024) - end - end - - def transfer_rate - bytes_per_second = @current.to_f / (Time.now - @start_time) - sprintf("%s/s", convert_bytes(bytes_per_second)) - end - - def bytes - convert_bytes(@current) - end - - def format_time (t) - t = t.to_i - sec = t % 60 - min = (t / 60) % 60 - hour = t / 3600 - sprintf("%02d:%02d:%02d", hour, min, sec); - end - - # ETA stands for Estimated Time of Arrival. - def eta - if @current == 0 - "ETA: --:--:--" - else - elapsed = Time.now - @start_time - eta = elapsed * @total / @current - elapsed; - sprintf("ETA: %s", format_time(eta)) - end - end - - def elapsed - elapsed = Time.now - @start_time - sprintf("Time: %s", format_time(elapsed)) - end - - def eol - if @finished_p then "\n" else "\r" end - end - - def do_percentage - if @total.zero? - 100 - else - @current * 100 / @total - end - end - - def get_width - # FIXME: I don't know how portable it is. - default_width = 80 - begin - tiocgwinsz = 0x5413 - data = [0, 0, 0, 0].pack("SSSS") - if @out.ioctl(tiocgwinsz, data) >= 0 then - rows, cols, xpixels, ypixels = data.unpack("SSSS") - if cols >= 0 then cols else default_width end - else - default_width - end - rescue Exception - default_width - end - end - - def show - arguments = @format_arguments.map {|method| - method = sprintf("fmt_%s", method) - send(method) - } - line = sprintf(@format, *arguments) - - width = get_width - if line.length == width - 1 - @out.print(line + eol) - @out.flush - elsif line.length >= width - @terminal_width = [@terminal_width - (line.length - width + 1), 0].max - if @terminal_width == 0 then @out.print(line + eol) else show end - else # line.length < width - 1 - @terminal_width += width - line.length + 1 - show - end - @previous_time = Time.now - end - - def show_if_needed - if @total.zero? - cur_percentage = 100 - prev_percentage = 0 - else - cur_percentage = (@current * 100 / @total).to_i - prev_percentage = (@previous * 100 / @total).to_i - end - - # Use "!=" instead of ">" to support negative changes - if cur_percentage != prev_percentage || - Time.now - @previous_time >= 1 || @finished_p - show - end - end - - public - def clear - @out.print "\r" - @out.print(" " * (get_width - 1)) - @out.print "\r" - end - - def finish - @current = @total - @finished_p = true - show - end - - def finished? - @finished_p - end - - def file_transfer_mode - @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer] - end - - def format= (format) - @format = format - end - - def format_arguments= (arguments) - @format_arguments = arguments - end - - def halt - @finished_p = true - show - end - - def inc (step = 1) - @current += step - @current = @total if @current > @total - show_if_needed - @previous = @current - end - - def set (count) - if count < 0 || count > @total - raise "invalid count: #{count} (total: #{@total})" - end - @current = count - show_if_needed - @previous = @current - end - - def inspect - "#" - end -end - -class ReversedProgressBar < ProgressBar - def do_percentage - 100 - super - end -end - diff --git a/spec/progress_bar/bar_spec.rb b/spec/progress_bar/bar_spec.rb new file mode 100644 index 00000000..5f40af42 --- /dev/null +++ b/spec/progress_bar/bar_spec.rb @@ -0,0 +1,148 @@ +require 'spec_helper' + +describe ProgressBar::Bar do + context "when a new bar is created" do + context "and no parameters are passed" do + before { @progressbar = ProgressBar::Bar.new } + + describe "#total" do + it "returns the default total" do + @progressbar.total.should eql ProgressBar::Bar::DEFAULT_TOTAL + end + end + + describe "#progress_mark" do + it "returns the default mark" do + @progressbar.progress_mark.should eql ProgressBar::Bar::DEFAULT_PROGRESS_MARK + end + end + + describe "#current" do + it "returns the default beginning position" do + @progressbar.current.should eql ProgressBar::Bar::DEFAULT_BEGINNING_POSITION + end + end + end + + context "and options are passed" do + before { @progressbar = ProgressBar::Bar.new(:total => 12, :progress_mark => "x", :beginning_position => 5) } + + describe "#total" do + it "returns the overridden total" do + @progressbar.total.should eql 12 + end + end + + describe "#progress_mark" do + it "returns the overridden mark" do + @progressbar.progress_mark.should eql "x" + end + end + + describe "#current" do + it "returns the overridden beginning position" do + @progressbar.current.should eql 5 + end + end + end + end + + context "when just begun" do + before { @progressbar = ProgressBar::Bar.new(:beginning_position => 0, :total => 50) } + + describe "#percentage_completed" do + it "calculates the amount" do + @progressbar.percentage_completed.should eql 0 + end + + it "displays the bar with no indication of progress" do + @progressbar.to_s(100).should eql " " + end + end + end + + context "when nothing has been completed" do + before { @progressbar = ProgressBar::Bar.new(:beginning_position => 0, :total => 50) } + + context "and the bar is incremented" do + before { @progressbar.increment } + + it "adds to the current amount" do + @progressbar.current.should eql 1 + end + + describe "#percentage_completed" do + it "calculates the amount completed" do + @progressbar.percentage_completed.should eql 2 + end + end + + describe "#to_s" do + it "displays the bar with an indication of progress" do + @progressbar.to_s(100).should eql "oo " + end + end + end + + describe "#percentage_completed" do + it "is zero" do + @progressbar.percentage_completed.should eql 0 + end + end + + describe "#to_s" do + it "displays the bar with no indication of progress" do + @progressbar.to_s(100).should eql " " + end + end + end + + context "when a fraction of a percentage has been completed" do + before { @progressbar = ProgressBar::Bar.new(:beginning_position => 1, :total => 200) } + + describe "#percentage_completed" do + it "always rounds down" do + @progressbar.percentage_completed.should eql 0 + end + end + + describe "#to_s" do + it "displays the bar with no indication of progress" do + @progressbar.to_s(100).should eql " " + end + end + end + + context "when completed" do + before { @progressbar = ProgressBar::Bar.new(:beginning_position => 50, :total => 50) } + + context "and the bar is incremented" do + before { @progressbar.increment } + + it "doesn't increment past the total" do + @progressbar.current.should eql 50 + @progressbar.percentage_completed.should eql 100 + end + + describe "#to_s" do + it "displays the bar as 100% complete" do + @progressbar.to_s(100).should eql "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + end + end + end + + describe "#to_s" do + it "displays the bar as 100% complete" do + @progressbar.to_s(100).should eql "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + end + end + end + + context "when attempting to set the bar's current value to be greater than the total" do + describe "#new" do + it "raises an error" do + lambda{ ProgressBar::Bar.new(:beginning_position => 11, :total => 10) }.should raise_error "You can't set the bar's current value to be greater than the total." + end + end + end +end diff --git a/spec/progress_bar/base_spec.rb b/spec/progress_bar/base_spec.rb new file mode 100644 index 00000000..582c2b2e --- /dev/null +++ b/spec/progress_bar/base_spec.rb @@ -0,0 +1,147 @@ +require 'spec_helper' +require 'stringio' + +describe ProgressBar::Base do + before do + @output_stream = StringIO.new("", "w+") + @progressbar = ProgressBar::Base.new(:output_stream => @output_stream, :length => 80) + end + + context "when a new bar is created" do + context "and no options are passed" do + before { @progressbar = ProgressBar::Base.new } + + describe "#title" do + it "returns the default title" do + @progressbar.title.should eql ProgressBar::Title::DEFAULT_TITLE + end + end + + describe "#out" do + it "returns the default output stream" do + @progressbar.send(:out).should eql ProgressBar::Base::DEFAULT_OUTPUT_STREAM + end + end + + describe "#length" do + it "returns the width of the terminal if it's a Unix environment" do + @progressbar.stub(:terminal_width).and_return(99) + @progressbar.send(:length).should eql 99 + end + end + + describe "#length" do + it "returns 80 if it's not a Unix environment" do + @progressbar.stub(:unix?).and_return(false) + @progressbar.send(:length).should eql 80 + end + end + end + + context "and options are passed" do + before { @progressbar = ProgressBar::Base.new(:title => "We All Float", :total => 12, :output_stream => STDOUT, :progress_mark => "x", :length => 88, :beginning_position => 5) } + + describe "#title" do + it "returns the overridden title" do + @progressbar.title.should eql "We All Float" + end + end + + describe "#out" do + it "returns the overridden output stream" do + @progressbar.send(:out).should eql STDOUT + end + end + + describe "#length" do + it "returns the overridden length" do + @progressbar.send(:length).should eql 88 + end + end + end + end + + describe "#clear" do + it "clears the current terminal line and/or bar text" do + @progressbar.clear + + @output_stream.rewind + @output_stream.read.should eql @progressbar.send(:clear_string) + end + end + + describe "#start" do + it "clears the current terminal line" do + @progressbar.start + + @output_stream.rewind + @output_stream.read.should match /^#{@progressbar.send(:clear_string)}/ + end + + it "prints the bar for the first time" do + @progressbar.start + + @output_stream.rewind + @output_stream.read.should match /Progress: \| \|\r\z/ + end + + it "prints correctly if passed a position to start at" do + @progressbar.start(:at => 20) + + @output_stream.rewind + @output_stream.read.should match /Progress: \|ooooooooooooo \|\r\z/ + end + end + + context "when the bar hasn't been completed" do + before { @progressbar = ProgressBar::Base.new(:length => 112, :beginning_position => 0, :total => 50, :output_stream => @output_stream) } + + describe "#increment" do + before { @progressbar.increment } + + it "displays the bar with the correct formatting" do + @output_stream.rewind + @output_stream.read.should match /Progress: \|oo \|\r\z/ + end + end + end + + context "when a new bar is created with a specific format" do + # %t: Left-Justified Title + # %T: Right-Justified Title + # %a: Elapsed (Absolute) Time + # %e: Estimated Time (Will Fall Back To 'ETA: ??:??:??' When It Exceeds 99:59:59) + # %E: Estimated Time (Will Fall Back To 'ETA: > 4 Days' When It Exceeds 99:59:59) + # %f: Force Estimated Time Even When Inaccurate + # %p: Percentage Complete (Integer) + # %P: Percentage Complete (Float) + # %c: Current Capacity + # %C: Total Capacity + # %b: Bar (Without End Caps) + # %B: Bar (Without End Caps And With Integrated Percentage) + # %r: Reversed Bar (Without End Caps) (Accumulates From The Right) + # %R: Reversed Bar (Without End Caps And With Integrated Percentage) + + # All values have an absolute length with the exception of %t, %T, %b, %B, %i, %r, %R and %I. + # The Titles will default to only being as long as their text. + # The Bars will all occupy any space left over. The minimum for the bars without end caps is 1. + # The minimum for the Bars with end caps is 3. + + # To specify a specific length for the title, use the "*\d" notation. + + # Add '@' after any Estimated Time flag to make it show the Elapsed Time when finished + context "#to_s" do + it "displays the title when passed the '%t' format tag" do + @progressbar.to_s('%t').should match /^Progress\z/ + end + + it "displays the title when passed the '%T' format tag" do + @progressbar.to_s('%T').should match /^Progress\z/ + end + + it "displays the bar when passed the '%b' format tag" do + @progressbar.to_s('%b').should match /^#{" " * 80}\z/ + end + end + end +end