mutant 0.9.3 → 0.9.8
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 +4 -4
- data/.github/workflows/ci.yml +121 -0
- data/Changelog.md +24 -0
- data/Gemfile +0 -15
- data/Gemfile.lock +56 -59
- data/Gemfile.shared +7 -0
- data/LICENSE +1 -1
- data/README.md +10 -1
- data/config/rubocop.yml +10 -3
- data/docs/commercial-support.md +14 -0
- data/lib/mutant.rb +4 -2
- data/lib/mutant/cli.rb +5 -5
- data/lib/mutant/integration.rb +1 -1
- data/lib/mutant/license.rb +2 -2
- data/lib/mutant/license/subscription/opensource.rb +1 -1
- data/lib/mutant/meta.rb +1 -3
- data/lib/mutant/meta/example/verification.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +0 -48
- data/lib/mutant/mutator/node/send.rb +1 -1
- data/lib/mutant/parallel.rb +1 -1
- data/lib/mutant/registry.rb +2 -7
- data/lib/mutant/reporter/cli/format.rb +1 -1
- data/lib/mutant/transform.rb +6 -5
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +2 -0
- data/mutant.gemspec +15 -13
- data/spec/integrations.yml +3 -1
- data/spec/support/corpus.rb +3 -3
- data/spec/support/ruby_vm.rb +1 -2
- data/spec/support/shared_context.rb +3 -3
- data/spec/support/xspec.rb +2 -2
- data/spec/unit/mutant/license_spec.rb +2 -2
- data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
- data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
- data/spec/unit/mutant/parallel_spec.rb +7 -7
- data/spec/unit/mutant/registry_spec.rb +52 -25
- data/spec/unit/mutant/repository/diff/ranges_spec.rb +2 -2
- metadata +44 -23
- data/.circleci/config.yml +0 -53
- data/lib/mutant/base.rb +0 -192
- data/lib/mutant/variable.rb +0 -282
- data/spec/unit/mutant/either_spec.rb +0 -247
- data/spec/unit/mutant/maybe_spec.rb +0 -60
- data/spec/unit/mutant/variable_spec.rb +0 -618
data/lib/mutant/base.rb
DELETED
@@ -1,192 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
module Functor
|
5
|
-
include AbstractType
|
6
|
-
|
7
|
-
abstract_method :fmap
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
# Raise error unless block is provided
|
12
|
-
#
|
13
|
-
# @raise [MissingBlockError]
|
14
|
-
# if no block is given
|
15
|
-
#
|
16
|
-
# @return [self]
|
17
|
-
def require_block
|
18
|
-
fail LocalJumpError unless block_given?
|
19
|
-
self
|
20
|
-
end
|
21
|
-
end # Functor
|
22
|
-
|
23
|
-
class Maybe
|
24
|
-
include(
|
25
|
-
AbstractType,
|
26
|
-
Adamantium::Flat,
|
27
|
-
Functor
|
28
|
-
)
|
29
|
-
|
30
|
-
class Nothing < self
|
31
|
-
instance = new
|
32
|
-
|
33
|
-
define_method(:new) { instance }
|
34
|
-
|
35
|
-
# Evaluate functor block
|
36
|
-
#
|
37
|
-
# @return [Maybe::Nothing]
|
38
|
-
def fmap(&block)
|
39
|
-
require_block(&block)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Evaluate applicative block
|
43
|
-
#
|
44
|
-
# @return [Maybe::Nothing]
|
45
|
-
def apply(&block)
|
46
|
-
require_block(&block)
|
47
|
-
end
|
48
|
-
end # Nothing
|
49
|
-
|
50
|
-
class Just < self
|
51
|
-
include Concord.new(:value)
|
52
|
-
|
53
|
-
# Evalute functor block
|
54
|
-
#
|
55
|
-
# @return [Maybe::Just<Object>]
|
56
|
-
def fmap
|
57
|
-
Just.new(yield(value))
|
58
|
-
end
|
59
|
-
|
60
|
-
# Evalute applicative block
|
61
|
-
#
|
62
|
-
# @return [Maybe]
|
63
|
-
def apply
|
64
|
-
yield(value)
|
65
|
-
end
|
66
|
-
end # Just
|
67
|
-
end # Maybe
|
68
|
-
|
69
|
-
class Either
|
70
|
-
include(
|
71
|
-
AbstractType,
|
72
|
-
Adamantium::Flat,
|
73
|
-
Concord.new(:value),
|
74
|
-
Functor
|
75
|
-
)
|
76
|
-
|
77
|
-
# Execute block and wrap error in left
|
78
|
-
#
|
79
|
-
# @param [Class:Exception] error
|
80
|
-
#
|
81
|
-
# @return [Either<Exception, Object>]
|
82
|
-
def self.wrap_error(error)
|
83
|
-
Right.new(yield)
|
84
|
-
rescue error => exception
|
85
|
-
Left.new(exception)
|
86
|
-
end
|
87
|
-
|
88
|
-
class Left < self
|
89
|
-
# Evaluate functor block
|
90
|
-
#
|
91
|
-
# @return [Either::Left<Object>]
|
92
|
-
def fmap(&block)
|
93
|
-
require_block(&block)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Evaluate applicative block
|
97
|
-
#
|
98
|
-
# @return [Either::Left<Object>]
|
99
|
-
def apply(&block)
|
100
|
-
require_block(&block)
|
101
|
-
end
|
102
|
-
|
103
|
-
# Unwrap value from left
|
104
|
-
#
|
105
|
-
# @return [Object]
|
106
|
-
def from_left
|
107
|
-
value
|
108
|
-
end
|
109
|
-
|
110
|
-
# Unwrap value from right
|
111
|
-
#
|
112
|
-
# @return [Object]
|
113
|
-
#
|
114
|
-
# rubocop:disable Style/GuardClause
|
115
|
-
def from_right
|
116
|
-
if block_given?
|
117
|
-
yield(value)
|
118
|
-
else
|
119
|
-
fail "Expected right value, got #{inspect}"
|
120
|
-
end
|
121
|
-
end
|
122
|
-
# rubocop:enable Style/GuardClause
|
123
|
-
|
124
|
-
# Map over left value
|
125
|
-
#
|
126
|
-
# @return [Either::Right<Object>]
|
127
|
-
def lmap
|
128
|
-
Left.new(yield(value))
|
129
|
-
end
|
130
|
-
|
131
|
-
# Evaluate left side of branch
|
132
|
-
#
|
133
|
-
# @param [#call] left
|
134
|
-
# @param [#call] _right
|
135
|
-
def either(left, _right)
|
136
|
-
left.call(value)
|
137
|
-
end
|
138
|
-
end # Left
|
139
|
-
|
140
|
-
class Right < self
|
141
|
-
# Evaluate functor block
|
142
|
-
#
|
143
|
-
# @return [Either::Right<Object>]
|
144
|
-
def fmap
|
145
|
-
Right.new(yield(value))
|
146
|
-
end
|
147
|
-
|
148
|
-
# Evaluate applicative block
|
149
|
-
#
|
150
|
-
# @return [Either<Object>]
|
151
|
-
def apply
|
152
|
-
yield(value)
|
153
|
-
end
|
154
|
-
|
155
|
-
# Unwrap value from left
|
156
|
-
#
|
157
|
-
# @return [Object]
|
158
|
-
#
|
159
|
-
# rubocop:disable Style/GuardClause
|
160
|
-
def from_left
|
161
|
-
if block_given?
|
162
|
-
yield(value)
|
163
|
-
else
|
164
|
-
fail "Expected left value, got #{inspect}"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
# rubocop:enable Style/GuardClause
|
168
|
-
|
169
|
-
# Unwrap value from right
|
170
|
-
#
|
171
|
-
# @return [Object]
|
172
|
-
def from_right
|
173
|
-
value
|
174
|
-
end
|
175
|
-
|
176
|
-
# Map over left value
|
177
|
-
#
|
178
|
-
# @return [Either::Right<Object>]
|
179
|
-
def lmap(&block)
|
180
|
-
require_block(&block)
|
181
|
-
end
|
182
|
-
|
183
|
-
# Evaluate right side of branch
|
184
|
-
#
|
185
|
-
# @param [#call] _left
|
186
|
-
# @param [#call] right
|
187
|
-
def either(_left, right)
|
188
|
-
right.call(value)
|
189
|
-
end
|
190
|
-
end # Right
|
191
|
-
end # Either
|
192
|
-
end # Mutant
|
data/lib/mutant/variable.rb
DELETED
@@ -1,282 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
# Lightweight shared variables
|
5
|
-
#
|
6
|
-
# ignore :reek:TooManyMethods
|
7
|
-
class Variable
|
8
|
-
EMPTY = Class.new do
|
9
|
-
const_set(:INSPECT, 'Mutant::Variable::EMPTY')
|
10
|
-
end.new.freeze
|
11
|
-
|
12
|
-
TIMEOUT = Class.new do
|
13
|
-
const_set(:INSPECT, 'Mutant::Variable::TIMEOUT')
|
14
|
-
end.new.freeze
|
15
|
-
|
16
|
-
# Result of operation that may time out
|
17
|
-
class Result
|
18
|
-
include AbstractType, Adamantium::Flat
|
19
|
-
|
20
|
-
# Test if take resulted in a timeout
|
21
|
-
#
|
22
|
-
# @return [Boolean]
|
23
|
-
#
|
24
|
-
# @api private
|
25
|
-
def timeout?
|
26
|
-
instance_of?(Timeout)
|
27
|
-
end
|
28
|
-
|
29
|
-
abstract_method :value
|
30
|
-
|
31
|
-
# Instance returned on timeouts
|
32
|
-
class Timeout < self
|
33
|
-
include Equalizer.new
|
34
|
-
|
35
|
-
INSTANCE = new
|
36
|
-
|
37
|
-
# Construct new object
|
38
|
-
#
|
39
|
-
# @return [Timeout]
|
40
|
-
def self.new
|
41
|
-
INSTANCE
|
42
|
-
end
|
43
|
-
end # Timeout
|
44
|
-
|
45
|
-
# Instance returned without timeouts
|
46
|
-
class Value < self
|
47
|
-
include Concord::Public.new(:value)
|
48
|
-
end # Value
|
49
|
-
end # Result
|
50
|
-
|
51
|
-
private_constant(*constants(false))
|
52
|
-
|
53
|
-
# Initialize object
|
54
|
-
#
|
55
|
-
# @param [Object] value
|
56
|
-
# the initial value
|
57
|
-
#
|
58
|
-
# @return [undefined]
|
59
|
-
def initialize(condition_variable:, mutex:, value: EMPTY)
|
60
|
-
@full = condition_variable.new
|
61
|
-
@mutex = mutex.new
|
62
|
-
@value = value
|
63
|
-
end
|
64
|
-
|
65
|
-
# Take value from mvar, block on empty
|
66
|
-
#
|
67
|
-
# @return [Object]
|
68
|
-
def take
|
69
|
-
synchronize do
|
70
|
-
wait_full
|
71
|
-
perform_take
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Take value from mvar, with timeout
|
76
|
-
#
|
77
|
-
# @param [Float] Timeout
|
78
|
-
#
|
79
|
-
# @return [Result::Timeout]
|
80
|
-
# in case take resulted in a timeout
|
81
|
-
#
|
82
|
-
# @return [Result::Value]
|
83
|
-
# in case take resulted in a value
|
84
|
-
def take_timeout(timeout)
|
85
|
-
synchronize do
|
86
|
-
if wait_timeout(@full, timeout, &method(:full?))
|
87
|
-
Result::Timeout.new
|
88
|
-
else
|
89
|
-
Result::Value.new(perform_take)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Read value from variable
|
95
|
-
#
|
96
|
-
# @return [Object]
|
97
|
-
# the contents of the mvar
|
98
|
-
def read
|
99
|
-
synchronize do
|
100
|
-
wait_full
|
101
|
-
@value
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Try put value into the variable, non blocking
|
106
|
-
#
|
107
|
-
# @param [Object] value
|
108
|
-
#
|
109
|
-
# @return [self]
|
110
|
-
def try_put(value)
|
111
|
-
synchronize do
|
112
|
-
perform_put(value) if empty?
|
113
|
-
end
|
114
|
-
|
115
|
-
self
|
116
|
-
end
|
117
|
-
|
118
|
-
# Execute block with value, blocking
|
119
|
-
#
|
120
|
-
# @yield [Object]
|
121
|
-
#
|
122
|
-
# @return [Object]
|
123
|
-
# the blocks return value
|
124
|
-
def with
|
125
|
-
synchronize do
|
126
|
-
wait_full
|
127
|
-
yield @value
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
private
|
132
|
-
|
133
|
-
# Perform the put
|
134
|
-
#
|
135
|
-
# @param [Object] value
|
136
|
-
def perform_put(value)
|
137
|
-
(@value = value).tap { @full.signal }
|
138
|
-
end
|
139
|
-
|
140
|
-
# Execute block under mutex
|
141
|
-
#
|
142
|
-
# @return [self]
|
143
|
-
def synchronize(&block)
|
144
|
-
@mutex.synchronize(&block)
|
145
|
-
end
|
146
|
-
|
147
|
-
# Wait for block predicate
|
148
|
-
#
|
149
|
-
# @param [ConditionVariable] event
|
150
|
-
#
|
151
|
-
# @return [undefined]
|
152
|
-
def wait(event)
|
153
|
-
event.wait(@mutex) until yield
|
154
|
-
end
|
155
|
-
|
156
|
-
# Wait with timeout for block predicate
|
157
|
-
#
|
158
|
-
# @param [ConditionVariable] event
|
159
|
-
#
|
160
|
-
# @return [Boolean]
|
161
|
-
# if wait was terminated due a timeout
|
162
|
-
#
|
163
|
-
# @return [undefined]
|
164
|
-
# otherwise
|
165
|
-
def wait_timeout(event, timeout)
|
166
|
-
loop do
|
167
|
-
break true if timeout <= 0
|
168
|
-
break if yield
|
169
|
-
timeout -= Timer.elapsed { event.wait(@mutex, timeout) }
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# Wait till mvar is full
|
174
|
-
#
|
175
|
-
# @return [undefined]
|
176
|
-
def wait_full
|
177
|
-
wait(@full, &method(:full?))
|
178
|
-
end
|
179
|
-
|
180
|
-
# Test if state is full
|
181
|
-
#
|
182
|
-
# @return [Boolean]
|
183
|
-
def full?
|
184
|
-
!empty?
|
185
|
-
end
|
186
|
-
|
187
|
-
# Test if state is empty
|
188
|
-
#
|
189
|
-
# @return [Boolean]
|
190
|
-
def empty?
|
191
|
-
@value.equal?(EMPTY)
|
192
|
-
end
|
193
|
-
|
194
|
-
# Shared variable that can be written at most once
|
195
|
-
#
|
196
|
-
# ignore :reek:InstanceVariableAssumption
|
197
|
-
class IVar < self
|
198
|
-
|
199
|
-
# Exception raised on ivar errors
|
200
|
-
class Error < RuntimeError; end
|
201
|
-
|
202
|
-
# Put valie into the mvar, raises if already full
|
203
|
-
#
|
204
|
-
# @param [Object] value
|
205
|
-
#
|
206
|
-
# @return [self]
|
207
|
-
#
|
208
|
-
# @raise Error
|
209
|
-
# if already full
|
210
|
-
def put(value)
|
211
|
-
synchronize do
|
212
|
-
fail Error, 'is immutable' if full?
|
213
|
-
perform_put(value)
|
214
|
-
end
|
215
|
-
|
216
|
-
self
|
217
|
-
end
|
218
|
-
|
219
|
-
private
|
220
|
-
|
221
|
-
# Perform take operation
|
222
|
-
#
|
223
|
-
# @return [Object]
|
224
|
-
def perform_take
|
225
|
-
@value
|
226
|
-
end
|
227
|
-
end # IVar
|
228
|
-
|
229
|
-
# Shared variable that can be written multiple times
|
230
|
-
#
|
231
|
-
# ignore :reek:InstanceVariableAssumption
|
232
|
-
class MVar < self
|
233
|
-
|
234
|
-
# Initialize object
|
235
|
-
#
|
236
|
-
# @param [Object] value
|
237
|
-
# the initial value
|
238
|
-
#
|
239
|
-
# @return [undefined]
|
240
|
-
def initialize(condition_variable:, mutex:, value: EMPTY)
|
241
|
-
super
|
242
|
-
@empty = condition_variable.new
|
243
|
-
end
|
244
|
-
|
245
|
-
# Put value into mvar, block on full
|
246
|
-
#
|
247
|
-
# @param [Object] value
|
248
|
-
#
|
249
|
-
# @return [self]
|
250
|
-
def put(value)
|
251
|
-
synchronize do
|
252
|
-
wait(@empty, &method(:empty?))
|
253
|
-
perform_put(value)
|
254
|
-
end
|
255
|
-
|
256
|
-
self
|
257
|
-
end
|
258
|
-
|
259
|
-
# Modify mvar
|
260
|
-
#
|
261
|
-
# @return [Object]
|
262
|
-
def modify
|
263
|
-
synchronize do
|
264
|
-
wait_full
|
265
|
-
perform_put(yield(@value))
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
private
|
270
|
-
|
271
|
-
# Empty the mvar
|
272
|
-
#
|
273
|
-
# @return [Object]
|
274
|
-
def perform_take
|
275
|
-
@value.tap do
|
276
|
-
@value = EMPTY
|
277
|
-
@empty.signal
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end # MVar
|
281
|
-
end # Variable
|
282
|
-
end # Mutant
|