console 1.29.2 → 1.36.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/context/command-line.md +47 -0
  4. data/context/configuration.md +23 -0
  5. data/context/events.md +71 -0
  6. data/context/getting-started.md +170 -0
  7. data/context/index.yaml +28 -0
  8. data/context/integration.md +37 -0
  9. data/lib/console/capture.rb +29 -3
  10. data/lib/console/clock.rb +9 -3
  11. data/lib/console/compatible/logger.rb +34 -3
  12. data/lib/console/config.rb +96 -0
  13. data/lib/console/event/failure.rb +33 -4
  14. data/lib/console/event/generic.rb +22 -1
  15. data/lib/console/event/spawn.rb +39 -7
  16. data/lib/console/event.rb +7 -1
  17. data/lib/console/filter.rb +83 -7
  18. data/lib/console/format/safe.rb +205 -58
  19. data/lib/console/format.rb +5 -1
  20. data/lib/console/interface.rb +18 -10
  21. data/lib/console/logger.rb +25 -38
  22. data/lib/console/output/default.rb +31 -6
  23. data/lib/console/output/failure.rb +9 -2
  24. data/lib/console/output/null.rb +5 -2
  25. data/lib/console/output/sensitive.rb +42 -1
  26. data/lib/console/output/serialized.rb +32 -7
  27. data/lib/console/output/split.rb +12 -1
  28. data/lib/console/output/terminal.rb +68 -15
  29. data/lib/console/output/wrapper.rb +12 -1
  30. data/lib/console/output.rb +14 -3
  31. data/lib/console/progress.rb +56 -9
  32. data/lib/console/resolver.rb +19 -2
  33. data/lib/console/terminal/formatter/failure.rb +18 -6
  34. data/lib/console/terminal/formatter/progress.rb +16 -3
  35. data/lib/console/terminal/formatter/spawn.rb +16 -5
  36. data/lib/console/terminal/formatter.rb +16 -0
  37. data/lib/console/terminal/text.rb +66 -20
  38. data/lib/console/terminal/xterm.rb +18 -3
  39. data/lib/console/terminal.rb +7 -9
  40. data/lib/console/version.rb +2 -2
  41. data/lib/console/warn.rb +2 -2
  42. data/lib/console.rb +2 -1
  43. data/license.md +6 -3
  44. data/readme.md +60 -6
  45. data/releases.md +115 -1
  46. data.tar.gz.sig +0 -0
  47. metadata +20 -12
  48. metadata.gz.sig +0 -0
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "wrapper"
7
7
 
8
8
  module Console
9
9
  module Output
10
+ # Redact sensitive information from output.
10
11
  class Sensitive < Wrapper
12
+ # Default redaction pattern.
11
13
  REDACT = /
12
14
  phone
13
15
  | email
@@ -34,28 +36,52 @@ module Console
34
36
  | password
35
37
  /xi
36
38
 
39
+ # Create a new sensitive output wrapper.
40
+ #
41
+ # @parameter output [Console::Output] The output to wrap.
42
+ # @parameter redact [Regexp] The pattern to redact.
43
+ # @parameter options [Hash] Additional options to pass to the output.
37
44
  def initialize(output, redact: REDACT, **options)
38
45
  super(output, **options)
39
46
 
40
47
  @redact = redact
41
48
  end
42
49
 
50
+ # Check if the given text should be redacted.
51
+ #
52
+ # @parameter text [String] The text to check.
53
+ # @returns [Boolean] Whether the text should be redacted.
43
54
  def redact?(text)
44
55
  text.match?(@redact)
45
56
  end
46
57
 
58
+ # Redact sensitive information from a hash.
59
+ #
60
+ # @parameter arguments [Hash] The hash to redact.
61
+ # @parameter filter [Proc] An optional filter to apply to redacted text.
62
+ # @returns [Hash] The redacted hash.
47
63
  def redact_hash(arguments, filter)
48
64
  arguments.transform_values do |value|
49
65
  redact(value, filter)
50
66
  end
51
67
  end
52
68
 
69
+ # Redact sensitive information from an array.
70
+ #
71
+ # @parameter array [Array] The array to redact.
72
+ # @parameter filter [Proc] An optional filter to apply to redacted text.
73
+ # @returns [Array] The redacted array.
53
74
  def redact_array(array, filter)
54
75
  array.map do |value|
55
76
  redact(value, filter)
56
77
  end
57
78
  end
58
79
 
80
+ # Redact sensitive information from the given argument.
81
+ #
82
+ # @parameter argument [String | Array | Hash] The argument to redact.
83
+ # @parameter filter [Proc] An optional filter to apply to redacted text.
84
+ # @returns [String | Array | Hash] The redacted argument.
59
85
  def redact(argument, filter)
60
86
  case argument
61
87
  when String
@@ -75,17 +101,32 @@ module Console
75
101
  end
76
102
  end
77
103
 
104
+ # A simple filter for redacting sensitive information.
78
105
  class Filter
106
+ # Create a new filter.
107
+ #
108
+ # @parameter substitutions [Hash] The substitutions to apply.
79
109
  def initialize(substitutions)
80
110
  @substitutions = substitutions
81
111
  @pattern = Regexp.union(substitutions.keys)
82
112
  end
83
113
 
114
+ # Apply the filter to the given text. This will replace all occurrences of the pattern with the corresponding substitution.
115
+ #
116
+ # @parameter text [String] The text to filter.
117
+ # @returns [String] The filtered text.
84
118
  def call(text)
85
119
  text.gsub(@pattern, @substitutions)
86
120
  end
87
121
  end
88
122
 
123
+ # Write a message to the output, filtering sensitive information if necessary.
124
+ #
125
+ # @parameter subject [String] The subject of the message.
126
+ # @parameter arguments [Array] The arguments to output.
127
+ # @parameter sensitive [Boolean | Filter | Hash] Whether to filter sensitive information.
128
+ # @parameter options [Hash] Additional options to pass to the output.
129
+ # @parameter block [Proc] An optional block to pass to the output.
89
130
  def call(subject = nil, *arguments, sensitive: true, **options, &block)
90
131
  if sensitive
91
132
  if sensitive.respond_to?(:call)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "../format"
7
7
  require "time"
@@ -9,9 +9,15 @@ require "fiber/annotation"
9
9
 
10
10
  module Console
11
11
  module Output
12
+ # Serialize log messages in a structured format.
12
13
  class Serialized
13
- def initialize(io, format: Format.default, **options)
14
- @io = io
14
+ # Create a new serialized output.
15
+ #
16
+ # @parameter io [IO] The output stream.
17
+ # @parameter format [Console::Format] The format to use for serializing log messages.
18
+ # @parameter options [Hash] Additional options to customize the output.
19
+ def initialize(stream, format: Format.default, **options)
20
+ @stream = stream
15
21
  @format = format
16
22
  end
17
23
 
@@ -20,21 +26,38 @@ module Console
20
26
  self
21
27
  end
22
28
 
23
- attr :io
29
+ # @attribute [IO] The output stream.
30
+ attr :stream
31
+
32
+ # @attribute [Console::Format] The format to use for serializing log messages.
24
33
  attr :format
25
34
 
35
+ # Serialize the given record.
36
+ #
37
+ # @parameter record [Hash] The record to serialize.
38
+ # @returns [String] The serialized record.
26
39
  def dump(record)
27
40
  @format.dump(record)
28
41
  end
29
42
 
43
+ # Output the given log message.
44
+ #
45
+ # @parameter subject [String] The subject of the log message.
46
+ # @parameter arguments [Array] The arguments to log.
47
+ # @parameter severity [Symbol] The severity of the log message.
48
+ # @parameter options [Hash] Additional options.
49
+ # @parameter block [Proc] An optional block used to generate the log message.
30
50
  def call(subject = nil, *arguments, severity: UNKNOWN, **options, &block)
31
51
  record = {
32
52
  time: Time.now.iso8601,
33
53
  severity: severity,
34
- oid: subject.object_id,
35
- pid: Process.pid,
54
+ process_id: Process.pid,
55
+ fiber_id: Fiber.current.object_id,
36
56
  }
37
57
 
58
+ # For backwards compatibility:
59
+ record[:pid] = record[:process_id]
60
+
38
61
  # We want to log just a brief subject:
39
62
  if subject.is_a?(String)
40
63
  record[:subject] = subject
@@ -42,6 +65,7 @@ module Console
42
65
  record[:subject] = subject.name
43
66
  else
44
67
  record[:subject] = subject.class.name
68
+ record[:object_id] = subject.object_id
45
69
  end
46
70
 
47
71
  if annotation = Fiber.current.annotation
@@ -68,10 +92,11 @@ module Console
68
92
 
69
93
  record.update(options)
70
94
 
71
- @io.puts(self.dump(record))
95
+ @stream.write(self.dump(record) << "\n")
72
96
  end
73
97
  end
74
98
 
99
+ # @deprecated This is a legacy constant, please use `Serialized` instead.
75
100
  JSON = Serialized
76
101
  end
77
102
  end
@@ -1,23 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022-2024, by Samuel Williams.
4
+ # Copyright, 2022-2025, by Samuel Williams.
5
5
 
6
6
  module Console
7
7
  module Output
8
+ # Split output into multiple outputs.
8
9
  class Split
10
+ # Create a new split output.
11
+ #
12
+ # @parameter outputs [Array(Console::Output)] The outputs to split into.
9
13
  def self.[](*outputs)
10
14
  self.new(outputs)
11
15
  end
12
16
 
17
+ # Create a new split output.
18
+ #
19
+ # @parameter outputs [Array(Console::Output)] The outputs to split into.
13
20
  def initialize(outputs)
14
21
  @outputs = outputs
15
22
  end
16
23
 
24
+ # Set the verbose flag for all outputs.
25
+ #
26
+ # @parameter value [Boolean] The new value.
17
27
  def verbose!(value = true)
18
28
  @outputs.each{|output| output.verbose!(value)}
19
29
  end
20
30
 
31
+ # Invoke the outputs. If a block is used, it may be invoked multiple times.
21
32
  def call(...)
22
33
  @outputs.each do |output|
23
34
  output.call(...)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
  # Copyright, 2021, by Robert Schulze.
6
6
 
7
7
  require_relative "../clock"
@@ -14,48 +14,66 @@ require "stringio"
14
14
 
15
15
  module Console
16
16
  module Output
17
+ # Represents a terminal output, and formats log messages for display.
17
18
  class Terminal
19
+ # Represents an output buffer that formats lines with a prefix.
18
20
  class Buffer < StringIO
21
+ # Create a new buffer with the given prefix.
22
+ #
23
+ # @parameter prefix [String] The prefix to use for each line.
19
24
  def initialize(prefix = nil)
20
25
  @prefix = prefix
21
26
 
22
27
  super()
23
28
  end
24
29
 
30
+ # @attribute [String] The prefix to use for each line.
25
31
  attr :prefix
26
32
 
27
- def puts(*args, prefix: @prefix)
28
- args.each do |arg|
33
+ # Write lines using the given prefix.
34
+ #
35
+ # @parameter lines [Array] The lines to write.
36
+ # @parameter prefix [String] The prefix to use for each line.
37
+ def puts(*lines, prefix: @prefix)
38
+ lines.each do |line|
29
39
  self.write(prefix) if prefix
30
- super(arg)
40
+ super(line)
31
41
  end
32
42
  end
33
43
 
44
+ # Write a line to the buffer.
34
45
  alias << puts
35
46
  end
36
47
 
37
- # This, and all related methods, is considered private.
48
+ # The environment variable used to store the start time of the console terminal output.
38
49
  CONSOLE_START_AT = "CONSOLE_START_AT"
39
50
 
40
- # Exports CONSOLE_START which can be used to synchronize the start times of all child processes when they log using delta time.
41
- def self.start_at!(environment = ENV)
42
- if time_string = environment[CONSOLE_START_AT]
51
+ # Exports CONSOLE_START_AT which can be used to synchronize the start times of all child processes when they log using delta time.
52
+ def self.start_at!(env = ENV)
53
+ if time_string = env[CONSOLE_START_AT]
43
54
  start_at = Time.parse(time_string) rescue nil
44
55
  end
45
56
 
46
57
  unless start_at
47
58
  start_at = Time.now
48
- environment[CONSOLE_START_AT] = start_at.to_s
59
+ env[CONSOLE_START_AT] = start_at.to_s
49
60
  end
50
61
 
51
62
  return start_at
52
63
  end
53
64
 
54
- def initialize(output, verbose: nil, start_at: Terminal.start_at!, format: nil, **options)
55
- @io = output
65
+ # Create a new terminal output.
66
+ #
67
+ # @parameter stream [IO] The output stream.
68
+ # @parameter verbose [Boolean] Whether to print verbose output.
69
+ # @parameter start_at [Time] The start time of the terminal output.
70
+ # @parameter format [Console::Terminal::Format] The format to use for terminal output.
71
+ # @parameter options [Hash] Additional options to customize the output.
72
+ def initialize(stream, verbose: nil, start_at: Terminal.start_at!, format: nil, **options)
73
+ @stream = stream
56
74
  @start_at = start_at
57
75
 
58
- @terminal = format.nil? ? Console::Terminal.for(@io) : format.new(@io)
76
+ @terminal = format.nil? ? Console::Terminal.for(@stream) : format.new(@stream)
59
77
 
60
78
  if verbose.nil?
61
79
  @verbose = !@terminal.colors?
@@ -78,22 +96,31 @@ module Console
78
96
  self.register_formatters
79
97
  end
80
98
 
81
- # This a final output that then writes to an IO object.
99
+ # This a final output.
82
100
  def last_output
83
101
  self
84
102
  end
85
103
 
86
- attr :io
104
+ # @attribute [IO] The output stream.
105
+ attr :stream
87
106
 
107
+ # @attribute [Boolean] Whether to print verbose output.
88
108
  attr_accessor :verbose
89
109
 
110
+ # @attribute [Time] The start time of the terminal output.
90
111
  attr :start
112
+
113
+ # @attribute [Console::Terminal::Format] The format to use for terminal output.
91
114
  attr :terminal
92
115
 
116
+ # Set the verbose output.
117
+ #
118
+ # @parameter value [Boolean] Whether to print verbose output.
93
119
  def verbose!(value = true)
94
120
  @verbose = value
95
121
  end
96
122
 
123
+ # Register all formatters in the given namespace.
97
124
  def register_formatters(namespace = Console::Terminal::Formatter)
98
125
  namespace.constants.each do |name|
99
126
  formatter = namespace.const_get(name)
@@ -101,8 +128,20 @@ module Console
101
128
  end
102
129
  end
103
130
 
131
+ # The default severity for log messages, if not specified.
104
132
  UNKNOWN = :unknown
105
133
 
134
+ # Log a message with the given severity.
135
+ #
136
+ # @parameter subject [String] The subject of the log message.
137
+ # @parameter arguments [Array] The arguments to log.
138
+ # @parameter name [String | Nil] The optional name of the log message, used as a prefix, otherwise defaults to the severity name.
139
+ # @parameter severity [Symbol] The severity of the log message.
140
+ # @parameter event [Hash] The event to log.
141
+ # @parameter options [Hash] Additional options.
142
+ # @yields {|buffer, terminal| ...} An optional block used to generate the log message.
143
+ # @parameter buffer [Console::Output::Terminal::Buffer] The output buffer.
144
+ # @parameter terminal [Console::Terminal] The terminal instance.
106
145
  def call(subject = nil, *arguments, name: nil, severity: UNKNOWN, event: nil, **options, &block)
107
146
  width = @terminal.width
108
147
 
@@ -134,7 +173,7 @@ module Console
134
173
  format_options(options, buffer)
135
174
  end
136
175
 
137
- @io.write buffer.string
176
+ @stream.write buffer.string
138
177
  end
139
178
 
140
179
  protected
@@ -242,13 +281,27 @@ module Console
242
281
  end
243
282
  end
244
283
 
284
+ # Terminal text output.
245
285
  module Text
286
+ # Create a new terminal output.
287
+ #
288
+ # @parameter output [IO] The output stream.
289
+ # @parameter options [Hash] Additional options to customize the output.
290
+ # @returns [Console::Output::Terminal] The terminal output instance.
246
291
  def self.new(output, **options)
247
292
  Terminal.new(output, format: Console::Terminal::Text, **options)
248
293
  end
249
294
  end
250
295
 
296
+ # Terminal XTerm output.
251
297
  module XTerm
298
+ # Create a new terminal output.
299
+ #
300
+ # You can use this to force XTerm output on a non-TTY output streams that support XTerm escape codes.
301
+ #
302
+ # @parameter output [IO] The output stream.
303
+ # @parameter options [Hash] Additional options to customize the output.
304
+ # @returns [Console::Output::Terminal] The terminal output instance.
252
305
  def self.new(output, **options)
253
306
  Terminal.new(output, format: Console::Terminal::XTerm, **options)
254
307
  end
@@ -1,25 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
6
  module Console
7
7
  module Output
8
+ # A generic wrapper for output handling.
8
9
  class Wrapper
10
+ # Create a new wrapper output.
11
+ #
12
+ # @parameter delegate [Console::Output] The output to delegate to.
13
+ # @parameter options [Hash] Additional options to customize the output.
9
14
  def initialize(delegate, **options)
10
15
  @delegate = delegate
11
16
  end
12
17
 
18
+ # @attribute [Console::Output] The output to delegate to.
13
19
  attr :delegate
14
20
 
21
+ # The last output is the last output of the delegate.
15
22
  def last_output
16
23
  @delegate.last_output
17
24
  end
18
25
 
26
+ # Set the verbose flag for the delegate.
27
+ #
28
+ # @parameter value [Boolean] The new value.
19
29
  def verbose!(value = true)
20
30
  @delegate.verbose!(value)
21
31
  end
22
32
 
33
+ # Invoke the delegate.
23
34
  def call(...)
24
35
  @delegate.call(...)
25
36
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "output/default"
7
7
  require_relative "output/serialized"
@@ -9,16 +9,27 @@ require_relative "output/terminal"
9
9
  require_relative "output/null"
10
10
 
11
11
  module Console
12
+ # Output handling.
12
13
  module Output
14
+ # Create a new output based on the environment.
15
+ #
16
+ # The environment variable `CONSOLE_OUTPUT` can be used to specify a list of output classes to wrap around the output. If not specified the {Default} output is used.
17
+ #
18
+ # The output argument is deliberately unders-specified but can be an IO object or an instance of {Output}.
19
+ #
20
+ # @parameter output [Console::Output] The output to wrap OR an IO object.
21
+ # @parameter env [Hash] The environment to read configuration from.
22
+ # @parameter options [Hash] Additional options to customize the output.
23
+ # @returns [Console::Output] The output instance.
13
24
  def self.new(output = nil, env = ENV, **options)
14
25
  if names = env["CONSOLE_OUTPUT"]
15
26
  names = names.split(",").reverse
16
27
 
17
28
  names.inject(output) do |output, name|
18
- Output.const_get(name).new(output, **options)
29
+ Output.const_get(name).new(output, env: env, **options)
19
30
  end
20
31
  else
21
- return Output::Default.new(output, **options)
32
+ return Output::Default.new(output, env: env, **options)
22
33
  end
23
34
  end
24
35
  end
@@ -1,22 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
  # Copyright, 2022, by Anton Sozontov.
6
6
 
7
7
  require_relative "clock"
8
8
 
9
9
  module Console
10
+ # A simple progress indicator
10
11
  class Progress
12
+ # @deprecated Use {Clock.now} instead.
11
13
  def self.now
12
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
14
+ Clock.now
13
15
  end
14
16
 
17
+ # Create a new progress indicator.
18
+ #
19
+ # @parameter subject [Object] The subject of the progress indicator.
20
+ # @parameter total [Integer] The total number of steps.
21
+ # @parameter minimum_output_duration [Numeric] The minimum duration between outputs.
22
+ # @parameter options [Hash] Additional options to customize the output.
15
23
  def initialize(subject, total = 0, minimum_output_duration: 0.1, **options)
16
24
  @subject = subject
17
25
  @options = options
18
26
 
19
- @start_time = Progress.now
27
+ @start_time = Clock.now
20
28
 
21
29
  @last_output_time = nil
22
30
  @minimum_output_duration = minimum_output_duration
@@ -25,34 +33,53 @@ module Console
25
33
  @total = total
26
34
  end
27
35
 
36
+ # @attribute [Object] The subject of the progress indicator.
28
37
  attr :subject
38
+
39
+ # @attribute [Numeric] The minimum duration between outputs.
40
+ attr :minimum_output_duration
41
+
42
+ # @attribute [Time] The time the progress indicator was started.
43
+ attr :start_time
44
+
45
+ # @attribute [Numeric] The current number of steps completed.
29
46
  attr :current
47
+
48
+ # @attribute [Numeric] The total number of steps.
30
49
  attr :total
31
50
 
51
+ # @returns [Numeric] The duration since the progress indicator was started.
32
52
  def duration
33
- Progress.now - @start_time
53
+ Clock.now - @start_time
34
54
  end
35
55
 
56
+ # @returns [Rational] The ratio of steps completed to total steps.
36
57
  def ratio
37
58
  Rational(@current.to_f, @total.to_f)
38
59
  end
39
60
 
61
+ # @returns [Numeric] The number of steps remaining.
40
62
  def remaining
41
63
  @total - @current
42
64
  end
43
65
 
66
+ # @returns [Numeric | Nil] The average duration per step, or `nil` if no steps have been completed.
44
67
  def average_duration
45
68
  if @current > 0
46
69
  duration / @current
47
70
  end
48
71
  end
49
72
 
73
+ # @returns [Numeric | Nil] The estimated remaining time, or `nil` if no steps have been completed.
50
74
  def estimated_remaining_time
51
75
  if average_duration = self.average_duration
52
76
  average_duration * remaining
53
77
  end
54
78
  end
55
79
 
80
+ # Generate an appropriate event for the progress indicator.
81
+ #
82
+ # @returns [Hash] The progress indicator as a hash.
56
83
  def to_hash
57
84
  Hash.new.tap do |hash|
58
85
  hash[:type] = :progress
@@ -64,30 +91,44 @@ module Console
64
91
  end
65
92
  end
66
93
 
94
+ # Increment the progress indicator by the given amount.
95
+ #
96
+ # @parameter amount [Numeric] The amount to increment by.
97
+ # @returns [Progress] The progress indicator itself.
67
98
  def increment(amount = 1)
68
99
  @current += amount
69
100
 
70
101
  if output?
71
102
  Console.call(@subject, self.to_s, event: self.to_hash, **@options)
72
- @last_output_time = Progress.now
103
+ @last_output_time = Clock.now
73
104
  end
74
105
 
75
106
  return self
76
107
  end
77
108
 
109
+ # Resize the progress indicator to the given total.
110
+ #
111
+ # @parameter total [Numeric] The new total number of steps.
112
+ # @returns [Progress] The progress indicator itself.
78
113
  def resize(total)
79
114
  @total = total
80
115
 
81
116
  Console.call(@subject, self.to_s, event: self.to_hash, **@options)
82
- @last_output_time = Progress.now
117
+ @last_output_time = Clock.now
83
118
 
84
119
  return self
85
120
  end
86
121
 
87
- def mark(*arguments, **options)
88
- Console.call(@subject, *arguments, **options, **@options)
122
+ # Augment the progress indicator with additional information.
123
+ #
124
+ # @parameter *arguments [Array] The arguments to log.
125
+ # @parameter **options [Hash] Additional options to log.
126
+ # @parameter &block [Proc] An optional block used to generate the log message.
127
+ def mark(*arguments, **options, &block)
128
+ Console.call(@subject, *arguments, **options, **@options, &block)
89
129
  end
90
130
 
131
+ # @returns [String] A human-readable representation of the progress indicator.
91
132
  def to_s
92
133
  if estimated_remaining_time = self.estimated_remaining_time
93
134
  "#{@current}/#{@total} completed in #{Clock.formatted_duration(self.duration)}, #{Clock.formatted_duration(estimated_remaining_time)} remaining."
@@ -98,12 +139,18 @@ module Console
98
139
 
99
140
  private
100
141
 
142
+ # Compute a time delta since the last output, used for rate limiting the output.
143
+ #
144
+ # @returns [Numeric | Nil] The duration since the last output.
101
145
  def duration_since_last_output
102
146
  if @last_output_time
103
- Progress.now - @last_output_time
147
+ Clock.now - @last_output_time
104
148
  end
105
149
  end
106
150
 
151
+ # Whether an output should be generated at this time, taking into account the remaining steps, and the duration since the last output.
152
+ #
153
+ # @returns [Boolean] Whether an output should be generated.
107
154
  def output?
108
155
  if remaining.zero?
109
156
  return true