mutant 0.14.2 → 0.15.1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/mutant +0 -7
  4. data/lib/mutant/ast/named_children.rb +0 -4
  5. data/lib/mutant/ast/nodes.rb +5 -0
  6. data/lib/mutant/ast/pattern/lexer.rb +0 -1
  7. data/lib/mutant/ast/structure.rb +10 -0
  8. data/lib/mutant/context.rb +2 -6
  9. data/lib/mutant/env.rb +8 -27
  10. data/lib/mutant/hooks.rb +2 -6
  11. data/lib/mutant/integration/null.rb +1 -3
  12. data/lib/mutant/integration.rb +2 -6
  13. data/lib/mutant/isolation/fork.rb +0 -2
  14. data/lib/mutant/matcher/method/instance.rb +2 -2
  15. data/lib/mutant/matcher/method.rb +0 -1
  16. data/lib/mutant/meta/example/verification.rb +0 -1
  17. data/lib/mutant/mutation/operators.rb +141 -44
  18. data/lib/mutant/mutation.rb +6 -18
  19. data/lib/mutant/mutator/node/and_asgn.rb +1 -0
  20. data/lib/mutant/mutator/node/binary.rb +5 -0
  21. data/lib/mutant/mutator/node/block.rb +10 -0
  22. data/lib/mutant/mutator/node/case_match.rb +46 -0
  23. data/lib/mutant/mutator/node/conditional_loop.rb +30 -1
  24. data/lib/mutant/mutator/node/define.rb +26 -0
  25. data/lib/mutant/mutator/node/defined.rb +1 -0
  26. data/lib/mutant/mutator/node/ensure.rb +24 -0
  27. data/lib/mutant/mutator/node/guard.rb +23 -0
  28. data/lib/mutant/mutator/node/in_pattern.rb +25 -0
  29. data/lib/mutant/mutator/node/literal/complex.rb +31 -0
  30. data/lib/mutant/mutator/node/literal/rational.rb +31 -0
  31. data/lib/mutant/mutator/node/literal/string.rb +1 -0
  32. data/lib/mutant/mutator/node/match_alt.rb +26 -0
  33. data/lib/mutant/mutator/node/match_pattern_p.rb +25 -0
  34. data/lib/mutant/mutator/node/op_asgn.rb +21 -1
  35. data/lib/mutant/mutator/node/or_asgn.rb +1 -4
  36. data/lib/mutant/mutator/node/regopt.rb +4 -6
  37. data/lib/mutant/mutator/node/rescue.rb +27 -0
  38. data/lib/mutant/mutator/node/send/binary.rb +45 -0
  39. data/lib/mutant/mutator/node/send.rb +23 -7
  40. data/lib/mutant/mutator/node/super.rb +2 -0
  41. data/lib/mutant/mutator/node/zsuper.rb +17 -0
  42. data/lib/mutant/mutator/node.rb +3 -9
  43. data/lib/mutant/mutator.rb +1 -3
  44. data/lib/mutant/parallel/connection.rb +9 -23
  45. data/lib/mutant/parallel/driver.rb +1 -5
  46. data/lib/mutant/parallel/source.rb +2 -1
  47. data/lib/mutant/parallel/worker.rb +8 -14
  48. data/lib/mutant/registry.rb +2 -1
  49. data/lib/mutant/reporter/cli/format.rb +4 -12
  50. data/lib/mutant/reporter/cli/printer/env_result.rb +9 -0
  51. data/lib/mutant/reporter/cli/printer.rb +2 -6
  52. data/lib/mutant/reporter/cli/progress_bar.rb +4 -12
  53. data/lib/mutant/reporter/cli.rb +6 -23
  54. data/lib/mutant/reporter/sequence.rb +1 -3
  55. data/lib/mutant/repository/diff.rb +1 -3
  56. data/lib/mutant/result.rb +16 -48
  57. data/lib/mutant/scope.rb +2 -6
  58. data/lib/mutant/segment.rb +1 -3
  59. data/lib/mutant/subject/method/instance.rb +3 -9
  60. data/lib/mutant/subject/method/metaclass.rb +1 -4
  61. data/lib/mutant/subject/method/singleton.rb +2 -8
  62. data/lib/mutant/subject/method.rb +3 -9
  63. data/lib/mutant/subject.rb +6 -18
  64. data/lib/mutant/timer.rb +2 -6
  65. data/lib/mutant/transform.rb +11 -33
  66. data/lib/mutant/usage.rb +6 -18
  67. data/lib/mutant/variable.rb +2 -6
  68. data/lib/mutant/version.rb +8 -14
  69. data/lib/mutant/world.rb +1 -3
  70. data/lib/mutant/zombifier.rb +3 -1
  71. data/lib/mutant.rb +8 -0
  72. metadata +39 -13
@@ -5,7 +5,8 @@ module Mutant
5
5
  class Connection
6
6
  include Anima.new(:marshal, :reader, :writer)
7
7
 
8
- Error = Class.new(RuntimeError)
8
+ class Error < RuntimeError
9
+ end
9
10
 
10
11
  HEADER_FORMAT = 'N'
11
12
  HEADER_SIZE = 4
@@ -21,13 +22,9 @@ module Mutant
21
22
 
22
23
  attr_reader :log
23
24
 
24
- def error
25
- Util.max_one(@errors)
26
- end
25
+ def error = Util.max_one(@errors)
27
26
 
28
- def result
29
- Util.max_one(@results)
30
- end
27
+ def result = Util.max_one(@results)
31
28
 
32
29
  def initialize(*)
33
30
  super
@@ -81,9 +78,7 @@ module Mutant
81
78
 
82
79
  private
83
80
 
84
- def timeout
85
- @errors << Timeout::Error
86
- end
81
+ def timeout = @errors << Timeout::Error
87
82
 
88
83
  def advance_result
89
84
  if length
@@ -96,9 +91,7 @@ module Mutant
96
91
  end
97
92
  end
98
93
 
99
- def length
100
- Util.max_one(@lengths)
101
- end
94
+ def length = Util.max_one(@lengths)
102
95
 
103
96
  def advance_log
104
97
  while with_nonblock_read(io: log_reader, max_bytes: MAX_LOG_CHUNK, &@log.public_method(:<<))
@@ -138,9 +131,7 @@ module Mutant
138
131
  class Frame
139
132
  include Anima.new(:io)
140
133
 
141
- def receive_value
142
- read(Util.one(read(HEADER_SIZE).unpack(HEADER_FORMAT)))
143
- end
134
+ def receive_value = read(Util.one(read(HEADER_SIZE).unpack(HEADER_FORMAT)))
144
135
 
145
136
  def send_value(body)
146
137
  bytesize = body.bytesize
@@ -160,14 +151,9 @@ module Mutant
160
151
  end
161
152
  end
162
153
 
163
- def receive_value
164
- marshal.load(reader.receive_value)
165
- end
154
+ def receive_value = marshal.load(reader.receive_value)
166
155
 
167
- def send_value(value)
168
- writer.send_value(marshal.dump(value))
169
- self
170
- end
156
+ def send_value(value) = tap { writer.send_value(marshal.dump(value)) }
171
157
 
172
158
  def self.from_pipes(marshal:, reader:, writer:)
173
159
  new(
@@ -38,11 +38,7 @@ module Mutant
38
38
  # This will cause all work to be immediately stopped.
39
39
  #
40
40
  # @return [self]
41
- def stop
42
- @alive = false
43
- threads.each(&:kill)
44
- self
45
- end
41
+ def stop = tap { @alive = false; threads.each(&:kill) }
46
42
 
47
43
  private
48
44
 
@@ -10,7 +10,8 @@ module Mutant
10
10
  include Adamantium, Anima.new(:index, :payload)
11
11
  end
12
12
 
13
- NoJobError = Class.new(RuntimeError)
13
+ class NoJobError < RuntimeError
14
+ end
14
15
 
15
16
  # Next job
16
17
  #
@@ -40,6 +40,10 @@ module Mutant
40
40
  world.stderr.reopen(log_writer)
41
41
  world.stdout.reopen(log_writer)
42
42
 
43
+ # Ensure output from background threads is immediately flushed
44
+ world.stderr.sync = true
45
+ world.stdout.sync = true
46
+
43
47
  run_child(
44
48
  config:,
45
49
  connection: Connection.from_pipes(marshal:, reader: request, writer: response),
@@ -77,9 +81,7 @@ module Mutant
77
81
  end
78
82
  private_class_method :run_child
79
83
 
80
- def index
81
- config.index
82
- end
84
+ def index = config.index
83
85
 
84
86
  # Run worker loop
85
87
  #
@@ -116,21 +118,13 @@ module Mutant
116
118
  # rubocop:enable Metrics/AbcSize
117
119
  # rubocop:enable Metrics/MethodLength
118
120
 
119
- def signal
120
- process.kill('TERM', pid)
121
- self
122
- end
121
+ def signal = tap { process.kill('TERM', pid) }
123
122
 
124
- def join
125
- process.wait(pid)
126
- self
127
- end
123
+ def join = tap { process.wait(pid) }
128
124
 
129
125
  private
130
126
 
131
- def process
132
- config.world.process
133
- end
127
+ def process = config.world.process
134
128
 
135
129
  def next_job
136
130
  config.var_source.with do |source|
@@ -13,7 +13,8 @@ module Mutant
13
13
  end
14
14
 
15
15
  # Raised when the type is an invalid type
16
- RegistryError = Class.new(TypeError)
16
+ class RegistryError < TypeError
17
+ end
17
18
 
18
19
  # Register class for AST node class
19
20
  #
@@ -44,9 +44,7 @@ module Mutant
44
44
  # Report delay in seconds
45
45
  #
46
46
  # @return [Float]
47
- def delay
48
- self.class::REPORT_DELAY
49
- end
47
+ def delay = self.class::REPORT_DELAY
50
48
 
51
49
  # Output abstraction to decouple tty? from buffer
52
50
  class Output
@@ -118,17 +116,11 @@ module Mutant
118
116
 
119
117
  private
120
118
 
121
- def new_buffer
122
- StringIO.new
123
- end
119
+ def new_buffer = StringIO.new
124
120
 
125
- def status_progressive_printer
126
- tty ? Printer::StatusProgressive::Tty : Printer::StatusProgressive::Pipe
127
- end
121
+ def status_progressive_printer = tty ? Printer::StatusProgressive::Tty : Printer::StatusProgressive::Pipe
128
122
 
129
- def test_status_progressive_printer
130
- tty ? Printer::Test::StatusProgressive::Tty : Printer::Test::StatusProgressive::Pipe
131
- end
123
+ def test_status_progressive_printer = tty ? Printer::Test::StatusProgressive::Tty : Printer::Test::StatusProgressive::Pipe
132
124
 
133
125
  # Wrap progress output with TTY-specific line handling
134
126
  #
@@ -8,10 +8,19 @@ module Mutant
8
8
  class EnvResult < self
9
9
  delegate(:failed_subject_results)
10
10
 
11
+ ALIVE_EXPLANATION = <<~'MESSAGE'
12
+ Alive mutations require one of two actions:
13
+ A) Keep the mutated code: Your tests specify the correct semantics,
14
+ and the original code is redundant. Accept the mutation.
15
+ B) Add a missing test: The original code is correct, but the tests
16
+ do not verify the behavior the mutation removed.
17
+ MESSAGE
18
+
11
19
  # Run printer
12
20
  #
13
21
  # @return [undefined]
14
22
  def run
23
+ puts(ALIVE_EXPLANATION) if failed_subject_results.any?
15
24
  visit_collection(SubjectResult, failed_subject_results)
16
25
  visit(EnvProgress, object)
17
26
  end
@@ -14,9 +14,7 @@ module Mutant
14
14
 
15
15
  private_class_method :new
16
16
 
17
- def call
18
- run
19
- end
17
+ def call = run
20
18
 
21
19
  # Create delegators to object
22
20
  #
@@ -50,9 +48,7 @@ module Mutant
50
48
 
51
49
  private
52
50
 
53
- def status_color
54
- success? ? Unparser::Color::GREEN : Unparser::Color::RED
55
- end
51
+ def status_color = success? ? Unparser::Color::GREEN : Unparser::Color::RED
56
52
 
57
53
  def visit_collection(printer, collection)
58
54
  collection.each do |object|
@@ -24,9 +24,7 @@ module Mutant
24
24
  # Render the progress bar string
25
25
  #
26
26
  # @return [String]
27
- def render
28
- "#{filled}#{empty}"
29
- end
27
+ def render = "#{filled}#{empty}"
30
28
 
31
29
  # Calculate percentage completion
32
30
  #
@@ -62,17 +60,11 @@ module Mutant
62
60
  [((current.to_f / total) * width).round, width].min
63
61
  end
64
62
 
65
- def empty_width
66
- width - filled_width
67
- end
63
+ def empty_width = width - filled_width
68
64
 
69
- def filled
70
- filled_char * filled_width
71
- end
65
+ def filled = filled_char * filled_width
72
66
 
73
- def empty
74
- empty_char * empty_width
75
- end
67
+ def empty = empty_char * empty_width
76
68
  end # ProgressBar
77
69
  end # CLI
78
70
  end # Reporter
@@ -26,55 +26,38 @@ module Mutant
26
26
  # @param [Env] env
27
27
  #
28
28
  # @return [self]
29
- def start(env)
30
- write(format.start(env))
31
- self
32
- end
29
+ def start(env) = tap { write(format.start(env)) }
33
30
 
34
31
  # Report test start
35
32
  #
36
33
  # @param [Env] env
37
34
  #
38
35
  # @return [self]
39
- def test_start(env)
40
- write(format.test_start(env))
41
- self
42
- end
36
+ def test_start(env) = tap { write(format.test_start(env)) }
43
37
 
44
38
  # Report progress object
45
39
  #
46
40
  # @param [Parallel::Status] status
47
41
  #
48
42
  # @return [self]
49
- def progress(status)
50
- write(format.progress(status))
51
- self
52
- end
43
+ def progress(status) = tap { write(format.progress(status)) }
53
44
 
54
45
  # Report progress object
55
46
  #
56
47
  # @return [self]
57
- def test_progress(status)
58
- write(format.test_progress(status))
59
- self
60
- end
48
+ def test_progress(status) = tap { write(format.test_progress(status)) }
61
49
 
62
50
  # Report delay in seconds
63
51
  #
64
52
  # @return [Float]
65
- def delay
66
- format.delay
67
- end
53
+ def delay = format.delay
68
54
 
69
55
  # Report warning
70
56
  #
71
57
  # @param [String] message
72
58
  #
73
59
  # @return [self]
74
- def warn(message)
75
- output.puts(message) if print_warnings
76
- self
77
- end
60
+ def warn(message) = tap { output.puts(message) if print_warnings }
78
61
 
79
62
  # Report env
80
63
  #
@@ -18,9 +18,7 @@ module Mutant
18
18
  # Minimum reporter delay
19
19
  #
20
20
  # @return [Float]
21
- def delay
22
- reporters.map(&:delay).min
23
- end
21
+ def delay = reporters.map(&:delay).min
24
22
 
25
23
  end # Sequence
26
24
  end # Reporter
@@ -44,9 +44,7 @@ module Mutant
44
44
  touched_paths.from_right { |message| fail Error, message }.fetch(path, &)
45
45
  end
46
46
 
47
- def touched_paths
48
- repository_root.bind(&method(:diff_index))
49
- end
47
+ def touched_paths = repository_root.bind(&method(:diff_index))
50
48
  memoize :touched_paths
51
49
 
52
50
  def diff_index(root)
data/lib/mutant/result.rb CHANGED
@@ -81,9 +81,7 @@ module Mutant
81
81
  # Failed subject results
82
82
  #
83
83
  # @return [Array<Result::Subject>]
84
- def failed_subject_results
85
- subject_results.reject(&:success?)
86
- end
84
+ def failed_subject_results = subject_results.reject(&:success?)
87
85
 
88
86
  sum :amount_mutation_results, :subject_results
89
87
  sum :amount_mutations_alive, :subject_results
@@ -94,9 +92,7 @@ module Mutant
94
92
  # Amount of mutations
95
93
  #
96
94
  # @return [Integer]
97
- def amount_mutations
98
- env.mutations.length
99
- end
95
+ def amount_mutations = env.mutations.length
100
96
 
101
97
  # Test if processing needs to stop
102
98
  #
@@ -126,34 +122,22 @@ module Mutant
126
122
  # Failed subject results
127
123
  #
128
124
  # @return [Array<Result::Test>]
129
- def failed_test_results
130
- test_results.reject(&:success?)
131
- end
125
+ def failed_test_results = test_results.reject(&:success?)
132
126
  memoize :failed_test_results
133
127
 
134
128
  def stop?
135
129
  env.config.fail_fast && !test_results.all?(&:success?)
136
130
  end
137
131
 
138
- def testtime
139
- test_results.map(&:runtime).sum(0.0)
140
- end
132
+ def testtime = test_results.map(&:runtime).sum(0.0)
141
133
 
142
- def amount_tests
143
- env.integration.all_tests.length
144
- end
134
+ def amount_tests = env.integration.all_tests.length
145
135
 
146
- def amount_test_results
147
- test_results.length
148
- end
136
+ def amount_test_results = test_results.length
149
137
 
150
- def amount_tests_failed
151
- failed_test_results.length
152
- end
138
+ def amount_tests_failed = failed_test_results.length
153
139
 
154
- def amount_tests_success
155
- test_results.count(&:passed)
156
- end
140
+ def amount_tests_success = test_results.count(&:passed)
157
141
  end # TestEnv
158
142
 
159
143
  # Test result
@@ -200,51 +184,37 @@ module Mutant
200
184
  # Alive mutations
201
185
  #
202
186
  # @return [Array<Result::Coverage>]
203
- def uncovered_results
204
- coverage_results.reject(&:success?)
205
- end
187
+ def uncovered_results = coverage_results.reject(&:success?)
206
188
  memoize :uncovered_results
207
189
 
208
190
  # Amount of mutations
209
191
  #
210
192
  # @return [Integer]
211
- def amount_mutation_results
212
- coverage_results.length
213
- end
193
+ def amount_mutation_results = coverage_results.length
214
194
 
215
195
  # Amount of mutations
216
196
  #
217
197
  # @return [Integer]
218
- def amount_timeouts
219
- coverage_results.count(&:timeout?)
220
- end
198
+ def amount_timeouts = coverage_results.count(&:timeout?)
221
199
 
222
200
  # Amount of mutations
223
201
  #
224
202
  # @return [Integer]
225
- def amount_mutations
226
- subject.mutations.length
227
- end
203
+ def amount_mutations = subject.mutations.length
228
204
 
229
205
  # Number of killed mutations
230
206
  #
231
207
  # @return [Integer]
232
- def amount_mutations_killed
233
- covered_results.length
234
- end
208
+ def amount_mutations_killed = covered_results.length
235
209
 
236
210
  # Number of alive mutations
237
211
  #
238
212
  # @return [Integer]
239
- def amount_mutations_alive
240
- uncovered_results.length
241
- end
213
+ def amount_mutations_alive = uncovered_results.length
242
214
 
243
215
  private
244
216
 
245
- def covered_results
246
- coverage_results.select(&:success?)
247
- end
217
+ def covered_results = coverage_results.select(&:success?)
248
218
  memoize :covered_results
249
219
 
250
220
  end # Subject
@@ -303,9 +273,7 @@ module Mutant
303
273
  # Time the tests had been running
304
274
  #
305
275
  # @return [Float]
306
- def killtime
307
- isolation_result.value&.runtime || 0.0
308
- end
276
+ def killtime = isolation_result.value&.runtime || 0.0
309
277
 
310
278
  # Test for timeout
311
279
  #
data/lib/mutant/scope.rb CHANGED
@@ -21,9 +21,7 @@ module Mutant
21
21
  # Unqualified name of scope
22
22
  #
23
23
  # @return [String]
24
- def unqualified_name
25
- name_nesting.last
26
- end
24
+ def unqualified_name = name_nesting.last
27
25
 
28
26
  # Match expressions for scope
29
27
  #
@@ -39,9 +37,7 @@ module Mutant
39
37
 
40
38
  private
41
39
 
42
- def name_nesting
43
- raw.name.split(NAMESPACE_DELIMITER)
44
- end
40
+ def name_nesting = raw.name.split(NAMESPACE_DELIMITER)
45
41
  memoize :name_nesting
46
42
 
47
43
  end # Scope
@@ -10,9 +10,7 @@ module Mutant
10
10
  :timestamp_start
11
11
  )
12
12
 
13
- def elapsed
14
- timestamp_end - timestamp_start
15
- end
13
+ def elapsed = timestamp_end - timestamp_start
16
14
 
17
15
  def offset_start(recording_start)
18
16
  timestamp_start - recording_start
@@ -12,15 +12,9 @@ module Mutant
12
12
  # Prepare subject for mutation insertion
13
13
  #
14
14
  # @return [self]
15
- def prepare
16
- scope.raw.undef_method(name)
17
- self
18
- end
19
-
20
- def post_insert
21
- scope.raw.__send__(visibility, name)
22
- self
23
- end
15
+ def prepare = tap { scope.raw.undef_method(name) }
16
+
17
+ def post_insert = tap { scope.raw.__send__(visibility, name) }
24
18
 
25
19
  # Mutator for memoizable memoized instance methods
26
20
  class Memoized < self
@@ -14,10 +14,7 @@ module Mutant
14
14
  # Prepare subject for mutation insertion
15
15
  #
16
16
  # @return [self]
17
- def prepare
18
- scope.raw.singleton_class.undef_method(name)
19
- self
20
- end
17
+ def prepare = tap { scope.raw.singleton_class.undef_method(name) }
21
18
 
22
19
  private
23
20
 
@@ -12,15 +12,9 @@ module Mutant
12
12
  # Prepare subject for mutation insertion
13
13
  #
14
14
  # @return [self]
15
- def prepare
16
- scope.raw.singleton_class.undef_method(name)
17
- self
18
- end
15
+ def prepare = tap { scope.raw.singleton_class.undef_method(name) }
19
16
 
20
- def post_insert
21
- scope.raw.singleton_class.__send__(visibility, name)
22
- self
23
- end
17
+ def post_insert = tap { scope.raw.singleton_class.__send__(visibility, name) }
24
18
 
25
19
  end # Singleton
26
20
  end # Method
@@ -9,9 +9,7 @@ module Mutant
9
9
  # Method name
10
10
  #
11
11
  # @return [Expression]
12
- def name
13
- node.children.fetch(self.class::NAME_INDEX)
14
- end
12
+ def name = node.children.fetch(self.class::NAME_INDEX)
15
13
 
16
14
  # Match expression
17
15
  #
@@ -28,16 +26,12 @@ module Mutant
28
26
  # Match expressions
29
27
  #
30
28
  # @return [Array<Expression>]
31
- def match_expressions
32
- [expression].concat(context.match_expressions)
33
- end
29
+ def match_expressions = [expression].concat(context.match_expressions)
34
30
  memoize :match_expressions
35
31
 
36
32
  private
37
33
 
38
- def scope
39
- context.scope
40
- end
34
+ def scope = context.scope
41
35
 
42
36
  end # Method
43
37
  end # Subject
@@ -37,23 +37,17 @@ module Mutant
37
37
  # Source path
38
38
  #
39
39
  # @return [Pathname]
40
- def source_path
41
- context.source_path
42
- end
40
+ def source_path = context.source_path
43
41
 
44
42
  # Prepare subject for insertion of mutation
45
43
  #
46
44
  # @return [self]
47
- def prepare
48
- self
49
- end
45
+ def prepare = self
50
46
 
51
47
  # Perform post insert cleanup
52
48
  #
53
49
  # @return [self]
54
- def post_insert
55
- self
56
- end
50
+ def post_insert = self
57
51
 
58
52
  # Source line range
59
53
  #
@@ -67,24 +61,18 @@ module Mutant
67
61
  # First source line
68
62
  #
69
63
  # @return [Integer]
70
- def source_line
71
- source_lines.begin
72
- end
64
+ def source_line = source_lines.begin
73
65
 
74
66
  # Identification string
75
67
  #
76
68
  # @return [String]
77
- def identification
78
- "#{expression.syntax}:#{source_path}:#{source_line}"
79
- end
69
+ def identification = "#{expression.syntax}:#{source_path}:#{source_line}"
80
70
  memoize :identification
81
71
 
82
72
  # Source representation of AST
83
73
  #
84
74
  # @return [String]
85
- def source
86
- Unparser.unparse(wrap_node(node))
87
- end
75
+ def source = Unparser.unparse(wrap_node(node))
88
76
  memoize :source
89
77
 
90
78
  # Match expression
data/lib/mutant/timer.rb CHANGED
@@ -48,16 +48,12 @@ module Mutant
48
48
  # Capture a deadline status
49
49
  #
50
50
  # @return [Status]
51
- def status
52
- Status.new(time_left:)
53
- end
51
+ def status = Status.new(time_left:)
54
52
 
55
53
  # Probe the time left
56
54
  #
57
55
  # @return [Float, nil]
58
- def time_left
59
- allowed_time - (timer.now - @start_at)
60
- end
56
+ def time_left = allowed_time - (timer.now - @start_at)
61
57
 
62
58
  # Deadline that never expires
63
59
  class None < self