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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23e8aecacb06e0bfe98467ac74b74f0b5e90ddc65f57069ae4bf29bdc7073b8a
4
- data.tar.gz: 6a220ecf6de03a768aeed0d4998983ada21d037859a9deafe6263b4604b201d7
3
+ metadata.gz: 28d2afab9d53f8fa8ebf80ec36ee2d0e1529d150a6ffd2993409ba845a3f4c79
4
+ data.tar.gz: 858dbf273be5fe62af6f0c74fbcfe51fd34f6491b344381f40fab71a053c50a1
5
5
  SHA512:
6
- metadata.gz: cb458d4d2a5169342ede984048be23c86d101db7546585e408e7470fe799f3344df4d2c691e42e43ff5ddd915e9af284a44ae59a7780890b06340a70a5e56419
7
- data.tar.gz: 6a8fc7aef7feec2b0c39af0f1478f1cebaf4ccb8667edcc0842d119019dec709998e2d0a3930869646b51a210f4758eaa2b721894b7a1b79d554f44294996ce3
6
+ metadata.gz: 337b2b031a41c3ba78e438b906fac942b98eaacff1e0c489d01e4811b5f676760cc8e0b9f2d6fbab27c1ec344c5f42d6c677546ce7fb43d52a17f89d0d38ac98
7
+ data.tar.gz: 5d3b42ff7fb6ee26873afc35217daeb43b9f431f05e251c59e3b112ab13f14481fc0f0d108d3f3cb53f3c458a531af5ca55c5821f058d5941949bc59a0eeae51
data/CHANGELOG CHANGED
@@ -1 +1,3 @@
1
+ 0.2.1 add support for estimation and re-use of default indicator with added concatted formatters
2
+ 0.2.0 various fixes and added unit tests
1
3
  0.0.1 initial version
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 `PoproFormatter::*` classes).
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 `PoproInfo` containing e.g. `current` and `total`.
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 `PoproIndicator` module).
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 `PoproIndicator` class is `PoproIndicator.default` (which returns an instance of `PoproIndicator::Stream`), which outputs the progress to STDOUT each time `Popro#did` or `Popro#will` is called.
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
 
@@ -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, _total = nil, **options, &block)
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.each0(obj, **options, &block)
22
- raise ConfigError, 'using :step is not supported in each0' if options.key?(:step)
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)
@@ -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 = obj.size if total.nil?
18
- @info.total += total if total.positive?
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 each0(obj, &block)
29
- each(obj, 0, &block)
30
- end
31
-
32
- def each_will(obj, titler, total = nil)
33
- each(obj, total) do |*args, **kwargs|
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 = 1)
54
+ def did(yielded = nil, amount = nil)
63
55
  @info.start unless @info.running?
64
- inc amount, yielded
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, use_block_result_as_title = nil, step = nil)
70
- @info.start unless @info.running?
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
- step = @step if step.nil?
76
- yielded = yield @context
77
- yielded = "#{WILL_CHECK_MARKS[1]} #{title}" unless title.nil? || use_block_result_as_title
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 inc(amount, yielded = nil)
91
- raise TypeError('expected an integer') unless amount.is_a? Integer
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.current += amount unless amount.zero?
94
- @indicator.call(@info, yielded)
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
@@ -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" + result.ljust(@longest, ' ')
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
@@ -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 || STDOUT
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
@@ -57,7 +57,6 @@ module Popro
57
57
 
58
58
  def to_h
59
59
  {
60
- started: @started,
61
60
  pct: pct,
62
61
  pct_formatted: pct_formatted,
63
62
  current: @current,
@@ -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[:step] ||= (block_given? ? 0 : 1)
16
- options[:progress] = self
17
- options[:info] = @info
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 each0 each_will to_proc did will formatter start done].each do |method_name|
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.0.1
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-06-01 00:00:00.000000000 Z
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: '0'
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: []