Skip to content

Instantly share code, notes, and snippets.

@epitron
Created March 25, 2010 14:13
Show Gist options
  • Save epitron/343594 to your computer and use it in GitHub Desktop.
Save epitron/343594 to your computer and use it in GitHub Desktop.
require 'progressbar'
class Mechanize
class Chain
class ResponseReader
def handle(ctx, params)
params[:response] = @response
body = StringIO.new
total = 0
if @response.respond_to? :content_type
pbar = ProgressBar.new(" |_ #{@response.content_type}", @response.content_length)
else
pbar = nil
end
@response.read_body { |part|
total += part.length
body.write(part)
pbar.set(total) if pbar
Mechanize.log.debug("Read #{total} bytes") if Mechanize.log
}
pbar.finish if pbar
body.rewind
res_klass = Net::HTTPResponse::CODE_TO_OBJ[@response.code.to_s]
raise ResponseCodeError.new(@response) unless res_klass
# Net::HTTP ignores EOFError if Content-length is given, so we emulate it here.
unless res_klass <= Net::HTTPRedirection
raise EOFError if (!params[:request].is_a?(Net::HTTP::Head)) && @response.content_length() && @response.content_length() != total
end
@response.each_header { |k,v|
Mechanize.log.debug("response-header: #{ k } => #{ v }")
} if Mechanize.log
params[:response_body] = body
params[:res_klass] = res_klass
super
end
end
end
end
#
# Ruby/ProgressBar - a text progress bar library
#
# Copyright (C) 2001-2005 Satoru Takabayashi <satoru@namazu.org>
# 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=nil, out = STDERR)
@title = title
@total = total
@out = out
@terminal_width = 80
@bar_mark = "."
@current = 0
@previous = 0
@finished_p = false
@start_time = Time.now
@previous_time = @start_time
@title_width = 18
#@format = "%-#{@title_width}s %3d%% %s %s"
if @total
#@format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
@format_arguments = [:title, :percentage, :stat_for_file_transfer]
else
@format_arguments = [:title, :stat_for_file_transfer]
end
clear
show
end
attr_reader :title
attr_reader :current
attr_reader :total
attr_accessor :start_time
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
"%3d%%" % do_percentage
end
def fmt_stat
if @finished_p then elapsed else eta end
end
def fmt_stat_for_file_transfer
if !@total or @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 = (@title[0,(@title_width - 1)] + ":")
@total ? "%-#{@title_width}s" % title : title
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|
send("fmt_#{method}")
}
#line = sprintf(@format, *arguments)
line = arguments.join(" ")
# 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
@out.print(line + eol)
@out.flush
@previous_time = Time.now
end
def show_if_needed
if @total
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
else
if Time.now - @previous_time >= 1 || @finished_p
show
end
end
end
public
def clear
@out.print "\r"
@out.print(" " * (get_width - 1))
@out.print "\r"
end
def finish
@current = @total if @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 @total and @current > @total
show_if_needed
@previous = @current
end
def set(count)
if @total and (count < 0 || count > @total)
raise "invalid count: #{count} (total: #{@total})"
end
@current = count
show_if_needed
@previous = @current
end
def inspect
"#<ProgressBar:#{@current}/#{@total}>"
end
end
class ReversedProgressBar < ProgressBar
def do_percentage
100 - super
end
end
if $0 == __FILE__
pb = ProgressBar.new("no_total")
5.times do
pb.inc 4000
sleep 1
end
pb.finish
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment