Skip to content

Instantly share code, notes, and snippets.

@denpatin
Created March 6, 2016 10:40
Show Gist options
  • Save denpatin/d489fd206707dda0941b to your computer and use it in GitHub Desktop.
Save denpatin/d489fd206707dda0941b to your computer and use it in GitHub Desktop.
Showing progress bar for each-ish methods
=begin
Usage examples:
big_array.each_with_progress(){ |e| ... }
(0...1000000).each_with_progress(){ |i| ... }
big_hash.each_key_with_progress(){ |k| ... }
IO.foreach_with_progress("big.txt"){ |line| ... }
open_with_progress("big.txt"){ |f| ... }
open("big.txt") do |f|
f.each_line_with_progress(){ |line| ... }
end
ARGF.each_line_with_progress(){ |line| ... }
=end
require "progressbar"
require "enumerator"
module Kernel
def open_with_progress(path, *args, &block)
File.open_with_progress(path, *args, &block)
end
end
class File
def self.open_with_progress(path, *args, &block)
open(path, *args) do |f|
f.with_progress() do
yield(f)
end
end
end
def with_progress(title = File.basename(self.path), &block)
pos = self.pos
seek(0, IO::SEEK_END)
size = self.pos
self.pos = pos
prog_bar = ProgressBar.new(title, size)
opened = true
thread = Thread.new() do
while opened
prog_bar.set(self.pos) rescue nil
sleep(0.1)
end
end
begin
yield()
ensure
opened = false
thread.join()
prog_bar.set(self.pos) rescue nil
prog_bar.halt()
end
end
end
class IO
def self.foreach_with_progress(path, &block)
File.open_with_progress(path) do |f|
f.each_line(&block)
end
end
end
class << ARGF
def with_progress(title = File.basename(self.path), &block)
if !self.file.is_a?(File)
yield()
else
paths = [self.file.path] + ARGV
file_poses = {}
total = 0
for path in paths
file_poses[path] = total
total += File.size(path)
end
prog_bar = ProgressBar.new("", total)
opened = true
thread = Thread.new() do
while opened
prog_bar.format =
("%-14s" % File.basename(self.file.path)).gsub(/%/, "%%") +
" %3d%% %s %s"
prog_bar.format_arguments = [:percentage, :bar, :stat]
prog_bar.set(file_poses[self.file.path] + self.pos) rescue nil
sleep(0.1)
end
end
begin
yield()
ensure
opened = false
thread.join()
begin
pos = self.closed? ? total : file_poses[self.file.path] + self.pos
prog_bar.set(pos)
rescue
end
prog_bar.halt()
end
end
end
def each_line_with_progress(rs = $/, &block)
with_progress() do
each_line(rs, &block)
end
end
end
module Enumerable
def each_with_progress(title = "", size = self.size, &block)
prog_bar = ProgressBar.new(title, size)
begin
each() do |*args|
args.size==1 ? yield(args[0]) : yield(*args)
prog_bar.inc()
end
ensure
prog_bar.halt()
end
end
end
class Hash
def each_key_with_progress(title = "", &block)
enum_for(:each_key).each_with_progress(title, self.size, &block)
end
def each_value_with_progress(title = "", &block)
enum_for(:each_value).each_with_progress(title, self.size, &block)
end
def each_pair_with_progress(title = "", &block)
enum_for(:each_pair).each_with_progress(title, self.size, &block)
end
end
class Range
def each_with_progress(title = "", &block)
if !self.begin.is_a?(Integer) || !self.end.is_a?(Integer)
raise(ArgumentError, "Both of begin and end must be Integer")
end
super(title, self.end - self.begin + (self.exclude_end? ? 0 : 1))
end
end
if $0 == __FILE__
case ARGV.shift()
when "argv"
ARGF.each_line_with_progress() do |line|
sleep(0.1)
end
when "file"
File.foreach_with_progress(ARGV[0]) do |line|
sleep(0.01)
end
when "array"
(0...10).to_a().each_with_progress("Array") do |i|
sleep(0.1)
end
when "range"
(0...10).each_with_progress("Range") do |i|
sleep(0.1)
end
when "hash"
Hash[*(0...20).to_a()].each_key_with_progress("Hash") do |i|
sleep(0.1)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment