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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +121 -0
  3. data/Changelog.md +24 -0
  4. data/Gemfile +0 -15
  5. data/Gemfile.lock +56 -59
  6. data/Gemfile.shared +7 -0
  7. data/LICENSE +1 -1
  8. data/README.md +10 -1
  9. data/config/rubocop.yml +10 -3
  10. data/docs/commercial-support.md +14 -0
  11. data/lib/mutant.rb +4 -2
  12. data/lib/mutant/cli.rb +5 -5
  13. data/lib/mutant/integration.rb +1 -1
  14. data/lib/mutant/license.rb +2 -2
  15. data/lib/mutant/license/subscription/opensource.rb +1 -1
  16. data/lib/mutant/meta.rb +1 -3
  17. data/lib/mutant/meta/example/verification.rb +1 -1
  18. data/lib/mutant/mutator/node/generic.rb +0 -48
  19. data/lib/mutant/mutator/node/send.rb +1 -1
  20. data/lib/mutant/parallel.rb +1 -1
  21. data/lib/mutant/registry.rb +2 -7
  22. data/lib/mutant/reporter/cli/format.rb +1 -1
  23. data/lib/mutant/transform.rb +6 -5
  24. data/lib/mutant/version.rb +1 -1
  25. data/lib/mutant/zombifier.rb +2 -0
  26. data/mutant.gemspec +15 -13
  27. data/spec/integrations.yml +3 -1
  28. data/spec/support/corpus.rb +3 -3
  29. data/spec/support/ruby_vm.rb +1 -2
  30. data/spec/support/shared_context.rb +3 -3
  31. data/spec/support/xspec.rb +2 -2
  32. data/spec/unit/mutant/license_spec.rb +2 -2
  33. data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
  34. data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
  35. data/spec/unit/mutant/parallel_spec.rb +7 -7
  36. data/spec/unit/mutant/registry_spec.rb +52 -25
  37. data/spec/unit/mutant/repository/diff/ranges_spec.rb +2 -2
  38. metadata +44 -23
  39. data/.circleci/config.yml +0 -53
  40. data/lib/mutant/base.rb +0 -192
  41. data/lib/mutant/variable.rb +0 -282
  42. data/spec/unit/mutant/either_spec.rb +0 -247
  43. data/spec/unit/mutant/maybe_spec.rb +0 -60
  44. data/spec/unit/mutant/variable_spec.rb +0 -618
@@ -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
@@ -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