popro 0.0.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +2 -0
- data/README.md +13 -6
- data/lib/popro.rb +4 -7
- data/lib/popro/context.rb +31 -32
- data/lib/popro/formatter.rb +48 -1
- data/lib/popro/indicator.rb +5 -4
- data/lib/popro/info.rb +0 -1
- data/lib/popro/progress.rb +25 -6
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28d2afab9d53f8fa8ebf80ec36ee2d0e1529d150a6ffd2993409ba845a3f4c79
|
4
|
+
data.tar.gz: 858dbf273be5fe62af6f0c74fbcfe51fd34f6491b344381f40fab71a053c50a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 337b2b031a41c3ba78e438b906fac942b98eaacff1e0c489d01e4811b5f676760cc8e0b9f2d6fbab27c1ec344c5f42d6c677546ce7fb43d52a17f89d0d38ac98
|
7
|
+
data.tar.gz: 5d3b42ff7fb6ee26873afc35217daeb43b9f431f05e251c59e3b112ab13f14481fc0f0d108d3f3cb53f3c458a531af5ca55c5821f058d5941949bc59a0eeae51
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
# Po'Pro: The Poor-Man's Progress Indicator
|
2
2
|
|
3
|
+
[![Version](https://badge.fury.io/rb/popro.svg)](https://badge.fury.io/rb/popro)
|
4
|
+
[![Tests](https://github.com/MikeSmithEU/PoPro/workflows/Code%20quality%20&%20unit%20tests/badge.svg)](https://github.com/MikeSmithEU/PoPro/actions?query=workflow%3A%22Code+quality+%26+unit+tests%22)
|
5
|
+
|
6
|
+
## Current TODOs
|
7
|
+
|
8
|
+
- [ ] properly update documentation
|
9
|
+
- [ ] simplify some stuff (each0?)
|
10
|
+
- [ ] 100% code coverage
|
11
|
+
|
3
12
|
## Why?
|
4
13
|
|
5
14
|
Easier and cleaner progress indication.
|
6
15
|
|
7
16
|
## How?
|
8
17
|
|
9
|
-
TODO: properly update documentation, simplify some stuff. 100% code coverage
|
10
|
-
|
11
18
|
### Basic usage
|
12
19
|
|
13
20
|
The invocation `Popro#did(yielded)` is used to signify that one step in progress has been finished.
|
@@ -263,11 +270,11 @@ end
|
|
263
270
|
## Formatters
|
264
271
|
|
265
272
|
You can set your own formatters using `Popro#formatter(&block)`. Each formatter can be a `Proc`, `block` or
|
266
|
-
class implementing the `call` method (e.g. the `
|
273
|
+
class implementing the `call` method (e.g. the `Popro::Formatter::*` classes).
|
267
274
|
|
268
275
|
The formatter will be invoked with 2 arguments:
|
269
276
|
|
270
|
-
1. `info`, an instance of `
|
277
|
+
1. `info`, an instance of `Popro::Info` containing e.g. `current` and `total`.
|
271
278
|
2. `yielded`, whatever was passed to the `Popro#did` method.
|
272
279
|
|
273
280
|
It can also be used inside blocks.
|
@@ -315,7 +322,7 @@ would output:
|
|
315
322
|
|
316
323
|
Indicator classes are responsible for communicating the progress (or not, as the case may be).
|
317
324
|
|
318
|
-
It is possible to provide your own "indicators" or use one of the provided ones (see `
|
325
|
+
It is possible to provide your own "indicators" or use one of the provided ones (see `Popro::Indicator` module).
|
319
326
|
|
320
|
-
The default `
|
327
|
+
The default `Popro::Indicator` class is `Popro::Indicator.default` (which returns an instance of `Popro::Indicator::Stream`), which outputs the progress to STDOUT each time `Popro#did` or `Popro#will` is called.
|
321
328
|
|
data/lib/popro.rb
CHANGED
@@ -7,22 +7,19 @@ module Popro
|
|
7
7
|
|
8
8
|
require_relative 'popro/progress'
|
9
9
|
|
10
|
-
def self.new(total, **options, &block)
|
10
|
+
def self.new(total = 0, **options, &block)
|
11
11
|
raise ConfigError, 'using :total is not supported in new' if options.key?(:total) && (options[:total] != total)
|
12
12
|
|
13
13
|
options[:total] = total
|
14
14
|
Progress.new(**options, &block)
|
15
15
|
end
|
16
16
|
|
17
|
-
def self.each(obj,
|
17
|
+
def self.each(obj, total = nil, **options, &block)
|
18
18
|
new(0, **options).each(obj, total, &block).done
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.
|
22
|
-
|
23
|
-
|
24
|
-
options[:step] = 0
|
25
|
-
each(obj, 0, **options, &block)
|
21
|
+
def self.each_will(obj, titler, total = nil, **options, &block)
|
22
|
+
new(0, **options).each_will(obj, titler, total, &block).done
|
26
23
|
end
|
27
24
|
|
28
25
|
def self.command_line(*_args)
|
data/lib/popro/context.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Popro
|
4
4
|
# the progress context passed as first argument to blocks (or named argument for `Progress#each` and `Popro.each`)
|
5
5
|
|
6
|
-
WILL_CHECK_MARKS ||= '
|
6
|
+
WILL_CHECK_MARKS ||= ' ✔'
|
7
7
|
|
8
8
|
class Context
|
9
9
|
def initialize(progress:, info:, indicator:, step: 1)
|
@@ -14,25 +14,17 @@ module Popro
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def each(obj, total = nil, &block)
|
17
|
-
total
|
18
|
-
|
19
|
-
block = proc { |d| d } unless block_given?
|
20
|
-
|
21
|
-
obj.each do |*args|
|
22
|
-
did block.call(*args, progress: self)
|
17
|
+
_each(obj, total) do |*args|
|
18
|
+
did block.call(*args, progress: @info)
|
23
19
|
end
|
24
|
-
|
25
|
-
self
|
26
20
|
end
|
27
21
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
kwargs[:progress].will titler.call(*args) do
|
35
|
-
yield(*args, **kwargs)
|
22
|
+
def each_will(obj, titler, total = nil, &block)
|
23
|
+
_each(obj, total) do |*args|
|
24
|
+
title = titler.call(*args)
|
25
|
+
will(title) do
|
26
|
+
block.call(*args, progress: @info)
|
27
|
+
nil
|
36
28
|
end
|
37
29
|
end
|
38
30
|
end
|
@@ -59,25 +51,25 @@ module Popro
|
|
59
51
|
block
|
60
52
|
end
|
61
53
|
|
62
|
-
def did(yielded = nil, amount =
|
54
|
+
def did(yielded = nil, amount = nil)
|
63
55
|
@info.start unless @info.running?
|
64
|
-
|
56
|
+
amount = @step if amount.nil?
|
57
|
+
raise TypeError, "amount: expected an integer, got #{amount.class}" unless amount.is_a? Integer
|
58
|
+
|
59
|
+
@info.current += amount unless amount.zero?
|
60
|
+
@indicator.call(@info, yielded)
|
65
61
|
|
66
62
|
self
|
67
63
|
end
|
68
64
|
|
69
|
-
def will(title = nil,
|
70
|
-
|
71
|
-
inc 0, "#{WILL_CHECK_MARKS[0]} #{title}"
|
65
|
+
def will(title = nil, step = nil, &block)
|
66
|
+
did "#{WILL_CHECK_MARKS[0]} #{title}", 0
|
72
67
|
|
73
68
|
return self unless block_given?
|
74
69
|
|
75
|
-
|
76
|
-
yielded =
|
77
|
-
yielded
|
78
|
-
|
79
|
-
# no need to communicate to Indicator if we are not advancing (avoid double calls)
|
80
|
-
did yielded, step unless step.zero?
|
70
|
+
block.call
|
71
|
+
yielded = "#{WILL_CHECK_MARKS[1]} #{title}"
|
72
|
+
did(yielded, step || @step)
|
81
73
|
yielded
|
82
74
|
end
|
83
75
|
|
@@ -87,11 +79,18 @@ module Popro
|
|
87
79
|
|
88
80
|
private
|
89
81
|
|
90
|
-
def
|
91
|
-
|
82
|
+
def _each(obj, total = nil, &block)
|
83
|
+
total = obj.size if total.nil?
|
84
|
+
raise TypeError, "total: expected an integer got #{total.class}" unless total.is_a?(Integer) || total.nil?
|
92
85
|
|
93
|
-
@info.
|
94
|
-
|
86
|
+
@info.total += total if total.positive?
|
87
|
+
# block = proc { |d| d } unless block_given?
|
88
|
+
|
89
|
+
obj.each do |*args, **kwargs|
|
90
|
+
block.call(*args, **kwargs)
|
91
|
+
end
|
92
|
+
|
93
|
+
self
|
95
94
|
end
|
96
95
|
end
|
97
96
|
end
|
data/lib/popro/formatter.rb
CHANGED
@@ -30,7 +30,7 @@ module Popro
|
|
30
30
|
def call(info, *args)
|
31
31
|
result = @formatter.call(info, *args)
|
32
32
|
@longest = [@longest, result.size].max
|
33
|
-
"\r
|
33
|
+
"\r#{result.ljust(@longest, ' ')}"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -43,6 +43,53 @@ module Popro
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
class Estimate
|
47
|
+
# TODO: cleaner implementation/formatstring
|
48
|
+
attr_reader :info
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
@start_time = current_time
|
52
|
+
@info = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def call(info, *_args)
|
56
|
+
@info = info
|
57
|
+
|
58
|
+
[
|
59
|
+
"estimated time left: #{format_duration(estimated_left)}",
|
60
|
+
"[#{format_duration(elapsed)}/#{format_duration(estimated_total)}]"
|
61
|
+
].join(', ')
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def elapsed
|
67
|
+
current_time - @start_time
|
68
|
+
end
|
69
|
+
|
70
|
+
def estimated_total
|
71
|
+
return nil if info.current.zero? || info.total.zero?
|
72
|
+
|
73
|
+
elapsed + (info.total / info.current) * elapsed
|
74
|
+
end
|
75
|
+
|
76
|
+
def estimated_left
|
77
|
+
return nil if info.current.zero? || info.total.zero?
|
78
|
+
|
79
|
+
(info.total / info.current) * elapsed
|
80
|
+
end
|
81
|
+
|
82
|
+
def format_duration(secs)
|
83
|
+
return '??d??h??m??s' if secs.nil?
|
84
|
+
|
85
|
+
format('%02dd%02dh%02dm%02ds', secs / 86_400, secs / 3600 % 24, secs / 60 % 60, secs % 60)
|
86
|
+
end
|
87
|
+
|
88
|
+
def current_time
|
89
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
46
93
|
class Sprintf
|
47
94
|
def initialize(format_string = nil)
|
48
95
|
@format_string = format_string
|
data/lib/popro/indicator.rb
CHANGED
@@ -27,7 +27,7 @@ module Popro
|
|
27
27
|
formatter = self.class.default_formatter(formatter) if formatter.nil? || formatter.is_a?(String)
|
28
28
|
|
29
29
|
@formatter = formatter
|
30
|
-
@stream = stream ||
|
30
|
+
@stream = stream || $stdout
|
31
31
|
end
|
32
32
|
|
33
33
|
def call(*args)
|
@@ -45,11 +45,12 @@ module Popro
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def self.default_formatter
|
48
|
+
def self.default_formatter(*extra_formatters)
|
49
49
|
::Popro::Formatter::RewriteLine.new(
|
50
50
|
::Popro::Formatter::Concat.new(
|
51
51
|
::Popro::Formatter::Spinner.new(:dots, bounce: true),
|
52
52
|
::Popro::Formatter::Sprintf.new,
|
53
|
+
*extra_formatters,
|
53
54
|
(proc do |_, yielded = nil|
|
54
55
|
yielded if yielded.is_a?(String) || yielded.is_a?(Numeric)
|
55
56
|
end),
|
@@ -58,8 +59,8 @@ module Popro
|
|
58
59
|
)
|
59
60
|
end
|
60
61
|
|
61
|
-
def self.default
|
62
|
-
Stream.new(formatter: default_formatter)
|
62
|
+
def self.default(*extra_formatters)
|
63
|
+
Stream.new(formatter: default_formatter(*extra_formatters))
|
63
64
|
end
|
64
65
|
end
|
65
66
|
end
|
data/lib/popro/info.rb
CHANGED
data/lib/popro/progress.rb
CHANGED
@@ -6,17 +6,24 @@ module Popro
|
|
6
6
|
require_relative 'info'
|
7
7
|
require_relative 'indicator'
|
8
8
|
|
9
|
+
DEFAULT_OPTIONS ||= {
|
10
|
+
total: 0,
|
11
|
+
current: 0,
|
12
|
+
indicator: Indicator.default
|
13
|
+
}.freeze
|
14
|
+
|
9
15
|
attr_reader :context
|
10
16
|
|
11
17
|
def initialize(**options)
|
12
18
|
@started = false
|
13
|
-
@info = Info.new(total: options.delete(:total), current: options.delete(:current))
|
14
19
|
|
15
|
-
options
|
16
|
-
|
17
|
-
|
18
|
-
options[:indicator] = Indicator.default unless options.key? :indicator
|
20
|
+
options = DEFAULT_OPTIONS
|
21
|
+
.merge(step: block_given? ? 0 : 1)
|
22
|
+
.merge(options)
|
19
23
|
|
24
|
+
@info = Info.new(total: options.delete(:total), current: options.delete(:current))
|
25
|
+
|
26
|
+
options.merge!(progress: self, info: @info)
|
20
27
|
@context = Context.new(**options)
|
21
28
|
|
22
29
|
register_aliases
|
@@ -26,15 +33,27 @@ module Popro
|
|
26
33
|
done
|
27
34
|
end
|
28
35
|
|
36
|
+
# increase the total
|
37
|
+
def add(amount)
|
38
|
+
@info.total += amount
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
29
42
|
private
|
30
43
|
|
31
44
|
def register_aliases
|
32
45
|
class << self
|
33
|
-
%i[each
|
46
|
+
%i[each each_will to_proc did will formatter start done].each do |method_name|
|
34
47
|
define_method method_name do |*args, &block|
|
35
48
|
@context.public_send(method_name, *args, &block)
|
36
49
|
end
|
37
50
|
end
|
51
|
+
|
52
|
+
%i[current total].each do |method_name|
|
53
|
+
define_method method_name do
|
54
|
+
@info.public_send(method_name)
|
55
|
+
end
|
56
|
+
end
|
38
57
|
end
|
39
58
|
end
|
40
59
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: popro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MikeSmithEU
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: The Poor-Man's Progress Indicator
|
14
|
-
email:
|
14
|
+
email:
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
@@ -31,7 +31,7 @@ homepage: https://rubygems.org/gems/popro
|
|
31
31
|
licenses:
|
32
32
|
- MIT
|
33
33
|
metadata: {}
|
34
|
-
post_install_message:
|
34
|
+
post_install_message:
|
35
35
|
rdoc_options: []
|
36
36
|
require_paths:
|
37
37
|
- lib
|
@@ -39,7 +39,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
39
|
requirements:
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '2.7'
|
43
43
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
47
|
version: '0'
|
48
48
|
requirements: []
|
49
49
|
rubygems_version: 3.1.2
|
50
|
-
signing_key:
|
50
|
+
signing_key:
|
51
51
|
specification_version: 4
|
52
52
|
summary: Po'Pro
|
53
53
|
test_files: []
|