dry-cli-ui 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d1ad3344ddfd395caef9b2ec0128f05cda8248a98afa864b1b61ed1d1db0b5e
4
- data.tar.gz: d55f3256373ec25c1201dd0c39525eeb49b50f16989806740f720ed3e59f0f13
3
+ metadata.gz: 7b4b7ae4869fa6a7623aafc109ef5c26af41436021cc62e4efd5ba87602c64a3
4
+ data.tar.gz: ecbc221a29f2a9be94a4041fd4642ac5367af9bd4b1e7cc4bff828da20e871c5
5
5
  SHA512:
6
- metadata.gz: fe5bb8356f594b5a8670ee7c8b9a5cdc0ec87e2480bea892f0e98389a8d43218fd2de162f77de9444990e3d197e7679352995f1da3eb234094df68a5ea5c2d25
7
- data.tar.gz: b982df4a36156203f92f39b3b3c8da0e9b5fe8672092333c09d7dd70e48759f0470fc82060dea4a16bdbc9daca3e219361ca0c7f95f114961b740b20354e2105
6
+ metadata.gz: d46a4ec8716f6aaea3f17d8e2eda6ba29f90272516d812270b77ba604ff372e6327c840cbcc54b9ac7511eabd78dcf709c8c6072932927e6ff72ff6c35a5931d
7
+ data.tar.gz: 0ce772edc045b9deca09aca086de303d7f01cc2ce7ff5ca912077eeb3a5753cd397bc9cdfc8c1b4704d0c125c67f8077176266fc693df6dcbe97a06a9f971850
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.6.0]
2
+
3
+ - `m.spinner(label)` inside `ui.multi_progress` declares a row with a spinner in place of a bar, for a phase whose size is never known, so one widget can show phases of known and unknown size together. The row shows its `Line`'s detail while it runs and ends `[✓] label`; it counts as a job and as no units on the headline.
4
+
1
5
  ## [0.5.1]
2
6
 
3
7
  - `ui.stoppable { |stop| ... }` makes Ctrl-C ask for a stop instead of interrupting, and `ui.multi_spinner` and `ui.multi_progress` take `stop:`. Once it is set, the jobs running finish, the rest are skipped, and the headline says `stopping`, then ends skipped. A second Ctrl-C interrupts. `Dry::CLI::UI::Stop` is the object behind it.
data/README.md CHANGED
@@ -399,6 +399,31 @@ Downloading...
399
399
 
400
400
  Any other `count:`, or a `total:` that is not a non-negative Integer, raises `ArgumentError`.
401
401
 
402
+ A phase whose size is never known goes on a row of its own with `m.spinner(label)`, beside the bars. Its row turns and shows the detail its `Line` is given, as in `multi_spinner`, with no bar, and it ends `[✓] label (0.1s)`, or `[𝘅] label: reason` after `line.fail`. It counts as a job and as no units, so `count: :jobs` suits a headline over phases run one at a time:
403
+
404
+ ```ruby
405
+ ui.multi_progress("Generating text", concurrent: false, count: :jobs) do |m|
406
+ m.spinner("Finding PDFs") { |line| pdfs = find_pdfs { |dir| line.detail = dir } }
407
+ m.progress("Extracting", total: nil) do |bar|
408
+ bar.total = pdfs.size
409
+ pdfs.each { |pdf| extract(pdf) && bar.advance }
410
+ end
411
+ m.spinner("Indexing") { index }
412
+ end
413
+ ```
414
+
415
+ Piped:
416
+
417
+ ```text
418
+ Generating text...
419
+ [✓] Finding PDFs (0.0s)
420
+ [✓] Extracting 3/3 (0.0s)
421
+ [✓] Indexing (0.0s)
422
+ ✓ Generating text 3/3 (0.0s)
423
+ ```
424
+
425
+ `m.spinner` without a block raises `ArgumentError`.
426
+
402
427
  Piped:
403
428
 
404
429
  ```text
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- dry-cli-ui (0.5.0)
4
+ dry-cli-ui (0.6.0)
5
5
  concurrent-ruby (~> 1.3)
6
6
  dry-cli (>= 1.0)
7
7
  pastel (~> 0.8)
@@ -84,7 +84,7 @@ CHECKSUMS
84
84
  dry-cli (1.4.1) sha256=b8015bb76c708aa8705a36faf694973e75eeeffca39b89c8e172dc6f66a7d874
85
85
  dry-cli-autocomplete (0.1.3) sha256=14f76447bda0000c71739b585c827dc0a0a763e30a68a8b4b2dff91f640768e4
86
86
  dry-cli-help (0.2.1) sha256=eaaaf6edb787ffe810425b4e4bb1a675d89397ccc759102d70b5b26e7bc692da
87
- dry-cli-ui (0.5.0)
87
+ dry-cli-ui (0.6.0)
88
88
  dry-inflector (1.3.1) sha256=7fb0c2bb04f67638f25c52e7ba39ab435d922a3a5c3cd196120f63accb682dcc
89
89
  forwardable (1.4.0) sha256=f1cd40cc9812937980e1c76f1aa053660990a7c9b6a98fc37d945468afcce838
90
90
  pastel (0.8.0) sha256=481da9fb7d2f6e6b1a08faf11fa10363172dc40fd47848f096ae21209f805a75
@@ -11,7 +11,7 @@ module Dry
11
11
  # Presentation helpers for Dry::CLI commands.
12
12
  module UI
13
13
  # The gem version.
14
- VERSION = "0.5.1"
14
+ VERSION = "0.6.0"
15
15
  end
16
16
  end
17
17
  end
@@ -11,6 +11,12 @@ module Dry
11
11
  # runs, and is replaced by `✓ label 120/120 (1.1s)` when it ends. The
12
12
  # bar's characters come from {Configuration#bar_format}.
13
13
  #
14
+ # A job declared with `spinner` instead has no bar: its row turns and
15
+ # shows its {Line}'s detail, as in {MultiSpinner}, and ends
16
+ # `✓ label (0.4s)`. It suits a phase whose size is never known, among
17
+ # phases whose size is. It counts as a job and as no units, so a
18
+ # headline over such rows reads best with `count: :jobs`.
19
+ #
14
20
  # @example
15
21
  # ui.multi_progress("Downloading") do |m|
16
22
  # files.each do |file|
@@ -20,6 +26,13 @@ module Dry
20
26
  # end
21
27
  # end
22
28
  #
29
+ # @example Phases, one at a time, some of known size
30
+ # ui.multi_progress("Generating", concurrent: false, count: :jobs) do |m|
31
+ # m.spinner("Finding") { |line| found = find { |dir| line.detail = dir } }
32
+ # m.progress("Extracting", total: nil) { |bar| bar.total = found.size; found.each { extract(it) && bar.advance } }
33
+ # m.spinner("Indexing") { index }
34
+ # end
35
+ #
23
36
  # See {Multi} for how the jobs run and how the rows are drawn.
24
37
  class MultiProgress < Multi
25
38
  # What the declaration block is given.
@@ -48,6 +61,20 @@ module Dry
48
61
  @jobs << Multi::Job.new(label, work, Progress::Handle.new(total, nil, color: Progress.color(color)))
49
62
  self
50
63
  end
64
+
65
+ # Declares a job with a spinner in place of a bar, for work whose
66
+ # size is never known.
67
+ #
68
+ # @param label [String]
69
+ # @yieldparam line [Line] reports on the work while it runs
70
+ # @return [self]
71
+ # @raise [ArgumentError] without a block
72
+ def spinner(label, &work)
73
+ raise ArgumentError, "spinner #{label.inspect} needs a block" unless work
74
+
75
+ @jobs << Multi::Job.new(label, work, Line.new)
76
+ self
77
+ end
51
78
  end
52
79
 
53
80
  # What the headline bar can count.
@@ -78,19 +105,37 @@ module Dry
78
105
  private
79
106
 
80
107
  # @param job [Job]
81
- # @return [Progress::Handle]
82
- def progress_of(job) = job.handle
108
+ # @return [Boolean] whether the job was declared with `spinner`
109
+ def spinner?(job) = job.handle.is_a?(Line)
110
+
111
+ # @param job [Job]
112
+ # @return [Object]
113
+ def call(job) = spinner?(job) ? Line.call(job.work, job.handle) : super
114
+
115
+ # @param job [Job]
116
+ # @return [Boolean]
117
+ def reported_failure?(job) = spinner?(job) && job.handle.failed?
118
+
119
+ # @param job [Job]
120
+ # @return [Progress::Handle, nil] nil for a spinner, which has no progress
121
+ def progress_of(job) = spinner?(job) ? nil : job.handle
83
122
 
84
123
  # @param job [Job]
85
124
  # @param width [Integer]
86
125
  # @return [String]
87
126
  def running(job, width)
127
+ return [job.label, job.handle.detail].reject(&:empty?).join(" ") if spinner?(job)
128
+
88
129
  "#{job.label.ljust(width)} #{meter(job.handle.current, job.handle.total, job.started, job.handle.color)}"
89
130
  end
90
131
 
91
132
  # @param job [Job]
92
133
  # @return [String]
93
- def summary(job) = "#{job.label} #{job.handle.current}/#{job.handle.total || '?'}"
134
+ def summary(job)
135
+ return job.handle.summary(job.label) if spinner?(job)
136
+
137
+ "#{job.label} #{job.handle.current}/#{job.handle.total || '?'}"
138
+ end
94
139
 
95
140
  # @param width [Integer]
96
141
  # @return [String]
@@ -105,7 +150,7 @@ module Dry
105
150
  def current
106
151
  return jobs.count(&:seconds) if @count == :jobs
107
152
 
108
- jobs.sum { |job| job.handle.current }
153
+ bars.sum { |job| job.handle.current }
109
154
  end
110
155
 
111
156
  # @return [Integer] the total given; or units across every job,
@@ -114,9 +159,12 @@ module Dry
114
159
  return @total if @total
115
160
  return jobs.size if @count == :jobs
116
161
 
117
- jobs.sum { |job| job.handle.total || job.handle.current }
162
+ bars.sum { |job| job.handle.total || job.handle.current }
118
163
  end
119
164
 
165
+ # @return [Array<Job>] the jobs that have a bar
166
+ def bars = jobs.reject { spinner?(it) }
167
+
120
168
  # `[◼◼◼ ] 48% 96/200 ETA 3.1s`, with the count right-aligned to
121
169
  # the widest any row can show, so every count ends in one column.
122
170
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-cli-ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -229,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
229
229
  - !ruby/object:Gem::Version
230
230
  version: '0'
231
231
  requirements: []
232
- rubygems_version: 4.0.20
232
+ rubygems_version: 4.0.22
233
233
  specification_version: 4
234
234
  summary: 'Runtime terminal UI for dry-cli commands: spinners, progress, boxes, task
235
235
  trees, tables, prompts'