Skip to content

Commit

Permalink
Change pipeline to inject progress bar instance only once
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrmurach committed Sep 16, 2020
1 parent a257bcc commit c89093e
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 29 deletions.
18 changes: 15 additions & 3 deletions lib/tty/progressbar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class ProgressBar

def_delegators :@meter, :rate, :mean_rate

def_delegator :@formatter, :use

# Determine terminal width
#
Expand Down Expand Up @@ -107,7 +106,7 @@ def initialize(format, options = {})
@meter = TTY::ProgressBar::Meter.new(interval)
@callbacks = Hash.new { |h, k| h[k] = [] }

@formatter.load
@formatter.load(self)
reset

@first_render = true
Expand Down Expand Up @@ -143,6 +142,19 @@ def attach_to(multibar)
@multibar = multibar
end

# Use custom token formatter
#
# @param [Object] formatter_class
# the formatter class to add to formatting pipeline
#
# @api public
def use(formatter_class)
unless formatter_class.is_a?(Class)
raise ArgumentError, "Formatter needs to be a class"
end
@formatter.use(formatter_class.new(self))
end

# Start progression by drawing bar and setting time
#
# @api public
Expand Down Expand Up @@ -287,7 +299,7 @@ def render
update(inset: self.class.display_columns(characters_in))
end

formatted = @formatter.decorate(self, @format)
formatted = @formatter.decorate(@format)
@tokens.each do |token, val|
formatted = formatted.gsub(":#{token}", val)
end
Expand Down
26 changes: 13 additions & 13 deletions lib/tty/progressbar/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,19 @@ def initialize(pipeline = nil)
# Prepare default pipeline formatters
#
# @api private
def load
@pipeline.use TTY::ProgressBar::CurrentFormatter
@pipeline.use TTY::ProgressBar::TotalFormatter
@pipeline.use TTY::ProgressBar::TotalByteFormatter
@pipeline.use TTY::ProgressBar::ElapsedFormatter
@pipeline.use TTY::ProgressBar::EstimatedFormatter
@pipeline.use TTY::ProgressBar::PercentFormatter
@pipeline.use TTY::ProgressBar::ByteFormatter
@pipeline.use TTY::ProgressBar::ByteRateFormatter
@pipeline.use TTY::ProgressBar::RateFormatter
@pipeline.use TTY::ProgressBar::MeanRateFormatter
@pipeline.use TTY::ProgressBar::MeanByteFormatter
@pipeline.use TTY::ProgressBar::BarFormatter
def load(progress)
@pipeline.use TTY::ProgressBar::CurrentFormatter.new(progress)
@pipeline.use TTY::ProgressBar::TotalFormatter.new(progress)
@pipeline.use TTY::ProgressBar::TotalByteFormatter.new(progress)
@pipeline.use TTY::ProgressBar::ElapsedFormatter.new(progress)
@pipeline.use TTY::ProgressBar::EstimatedFormatter.new(progress)
@pipeline.use TTY::ProgressBar::PercentFormatter.new(progress)
@pipeline.use TTY::ProgressBar::ByteFormatter.new(progress)
@pipeline.use TTY::ProgressBar::ByteRateFormatter.new(progress)
@pipeline.use TTY::ProgressBar::RateFormatter.new(progress)
@pipeline.use TTY::ProgressBar::MeanRateFormatter.new(progress)
@pipeline.use TTY::ProgressBar::MeanByteFormatter.new(progress)
@pipeline.use TTY::ProgressBar::BarFormatter.new(progress)
end
end # Formatter
end # ProgressBar
Expand Down
17 changes: 11 additions & 6 deletions lib/tty/progressbar/pipeline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,29 @@ def initialize(formatters = [])
# Add a new formatter
#
# @example
# use(TTY::ProgressBar::TotalFormatter)
# use(TTY::ProgressBar::TotalFormatter.new(progress_bar))
#
# @api public
def use(formatter)
formatters << proc { |progress| formatter.new(progress) }
formatters << formatter
end

# Decorate the tokenized string with actual values
#
# @example
# decorate("[:bar] :current :elapsed")
#
# @param [String] tokenized
# the string with tokens
#
# @return [nil]
#
# @api private
def decorate(progress, tokenized)
def decorate(tokenized)
base = tokenized.dup
formatters.inject(base) do |formatted, formatter|
instance = formatter.call(progress)
if instance.respond_to?(:matches?) && instance.matches?(formatted)
instance.format(formatted)
if formatter.respond_to?(:matches?) && formatter.matches?(formatted)
formatter.format(formatted)
else
formatted
end
Expand Down
4 changes: 2 additions & 2 deletions spec/perf/render_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@
}.at_most(10).times
end

it "performs bar rendering 2.3k i/s" do
it "performs bar rendering 2.4k i/s" do
output = StringIO.new
progress = described_class.new("[:bar]", output: output, total: 10,
width: 10)

expect {
progress.advance
progress.reset
}.to perform_at_least(2300).ips
}.to perform_at_least(2400).ips
end
end
10 changes: 10 additions & 0 deletions spec/unit/custom_formatter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,14 @@ def format(value)
output.rewind
expect(output.read).to eq("\e[1GHello")
end

it "enforces class formatter" do
progress = TTY::ProgressBar.new(":hi", output: output, total: 10)
stub_const("HiFormatter", Class.new)
formatter = HiFormatter.new

expect {
progress.use(formatter)
}.to raise_error(ArgumentError, "Formatter needs to be a class")
end
end
11 changes: 6 additions & 5 deletions spec/unit/pipeline_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
subject(:pipeline) { described_class.new }

it "decorates tokenized string with pipeline formatters" do
pipeline.use TTY::ProgressBar::CurrentFormatter
pipeline.use TTY::ProgressBar::TotalFormatter
progress_bar = double(current: '3', total: '10')
pipeline.use TTY::ProgressBar::CurrentFormatter.new(progress_bar)
pipeline.use TTY::ProgressBar::TotalFormatter.new(progress_bar)
tokenized = "[:current/:total]"
expect(pipeline.decorate(progress_bar, tokenized)).to eq("[3/10]")
expect(pipeline.decorate(tokenized)).to eq("[3/10]")
end

it "enumerates pipeline formatters" do
pipeline.use TTY::ProgressBar::CurrentFormatter
pipeline.use TTY::ProgressBar::TotalFormatter
progress_bar = double(current: '3', total: '10')
pipeline.use TTY::ProgressBar::CurrentFormatter.new(progress_bar)
pipeline.use TTY::ProgressBar::TotalFormatter.new(progress_bar)
yielded = []
pipeline.each { |formatter| yielded << formatter }
expect(yielded.size).to eq(2)
Expand Down

0 comments on commit c89093e

Please sign in to comment.