mutant 0.6.7 → 0.7.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.
- checksums.yaml +4 -4
- data/Changelog.md +10 -0
- data/README.md +1 -1
- data/config/flay.yml +1 -1
- data/config/reek.yml +11 -40
- data/config/rubocop.yml +1 -1
- data/lib/mutant.rb +10 -2
- data/lib/mutant/actor.rb +64 -0
- data/lib/mutant/actor/actor.rb +50 -0
- data/lib/mutant/actor/env.rb +35 -0
- data/lib/mutant/actor/mailbox.rb +53 -0
- data/lib/mutant/actor/receiver.rb +48 -0
- data/lib/mutant/actor/sender.rb +27 -0
- data/lib/mutant/ast/types.rb +1 -1
- data/lib/mutant/cli.rb +2 -0
- data/lib/mutant/config.rb +2 -1
- data/lib/mutant/env.rb +6 -2
- data/lib/mutant/expression/methods.rb +1 -1
- data/lib/mutant/integration.rb +11 -1
- data/lib/mutant/isolation.rb +1 -2
- data/lib/mutant/meta/example.rb +1 -1
- data/lib/mutant/mutation.rb +47 -21
- data/lib/mutant/mutator/node.rb +1 -1
- data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +4 -3
- data/lib/mutant/reporter/cli.rb +2 -0
- data/lib/mutant/reporter/cli/format.rb +23 -36
- data/lib/mutant/reporter/cli/printer.rb +66 -27
- data/lib/mutant/result.rb +45 -58
- data/lib/mutant/runner.rb +47 -154
- data/lib/mutant/runner/master.rb +174 -0
- data/lib/mutant/runner/scheduler.rb +141 -0
- data/lib/mutant/runner/worker.rb +93 -0
- data/lib/mutant/subject/method/instance.rb +1 -15
- data/lib/mutant/test.rb +2 -15
- data/lib/mutant/version.rb +1 -1
- data/meta/send.rb +16 -0
- data/mutant-rspec.gemspec +1 -1
- data/mutant.gemspec +1 -1
- data/spec/integration/mutant/rspec_spec.rb +0 -6
- data/spec/spec_helper.rb +9 -1
- data/spec/support/fake_actor.rb +93 -0
- data/spec/support/shared_context.rb +135 -0
- data/spec/unit/mutant/actor/actor_spec.rb +35 -0
- data/spec/unit/mutant/actor/binding_spec.rb +32 -0
- data/spec/unit/mutant/actor/env_spec.rb +49 -0
- data/spec/unit/mutant/actor/message_spec.rb +23 -0
- data/spec/unit/mutant/actor/receiver_spec.rb +60 -0
- data/spec/unit/mutant/actor/sender_spec.rb +22 -0
- data/spec/unit/mutant/cli_spec.rb +17 -4
- data/spec/unit/mutant/env_spec.rb +2 -2
- data/spec/unit/mutant/mailbox_spec.rb +33 -0
- data/spec/unit/mutant/mutation_spec.rb +52 -18
- data/spec/unit/mutant/mutator/registry_spec.rb +4 -4
- data/spec/unit/mutant/reporter/cli_spec.rb +131 -249
- data/spec/unit/mutant/result/env_spec.rb +55 -0
- data/spec/unit/mutant/result/subject_spec.rb +43 -0
- data/spec/unit/mutant/runner/master_spec.rb +199 -0
- data/spec/unit/mutant/runner/scheduler_spec.rb +161 -0
- data/spec/unit/mutant/runner/worker_spec.rb +73 -0
- data/spec/unit/mutant/runner_spec.rb +60 -118
- data/spec/unit/mutant/subject/method/instance_spec.rb +18 -31
- data/spec/unit/mutant/warning_filter_spec.rb +1 -1
- metadata +39 -14
- data/lib/mutant/runner/collector.rb +0 -133
- data/lib/mutant/warning_expectation.rb +0 -47
- data/spec/unit/mutant/runner/collector_spec.rb +0 -198
- data/spec/unit/mutant/test_spec.rb +0 -23
- data/spec/unit/mutant/warning_expectation_spec.rb +0 -80
- data/test_app/Gemfile.rspec2 +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 607569850361ac4088176c89f75ac7f7d732d8f0
|
4
|
+
data.tar.gz: 3247e38171198bf00c53341447881cb76fa44a3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 888a9f29aa202635ece333e17c514ca52c7a28660e0ab8cd7f4397f4f108be3a8d91477812ad48ae970f2808b1516de084f44ff02f743b21174ad2504fb4cdae
|
7
|
+
data.tar.gz: 5e3faa4096046383aa51274b6f201fb3f1eb416d7f8ca8049505fcf823fd994f051c34dd159256a6926e56401f5270d859b0bad0f13b645101442bfff5e80ef6
|
data/Changelog.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# v0.7.1 2014-12-04
|
2
|
+
|
3
|
+
* Fix invalid dependencies on rspec for mutant-rspec
|
4
|
+
|
5
|
+
# v0.7.0 2014-12-04
|
6
|
+
|
7
|
+
* Use homegrown actor based parallelization
|
8
|
+
* Fix redundant spec execution in rspec integration
|
9
|
+
* Add mutation from #send to #__send__ (the canonical form).
|
10
|
+
|
1
11
|
# v0.6.7 2014-11-17
|
2
12
|
|
3
13
|
* Fix duplicate neutral emit for memoized instance method subjects
|
data/README.md
CHANGED
@@ -97,7 +97,7 @@ This can have the following unintended effects:
|
|
97
97
|
counts the mutation as killed.
|
98
98
|
|
99
99
|
* MRI crashes with a segfault and gets stuck when handling the segfault.
|
100
|
-
Depending on the number of active kill jobs mutant might appear to continue normally
|
100
|
+
Depending on the number of active kill jobs mutant might appear to continue normally until
|
101
101
|
all workers are stuck into this state when it begins to hang.
|
102
102
|
Currently mutant must assume that your test suite simply not terminated yet as from the outside
|
103
103
|
(parent process) the difference between a long running test and a stuck MRI is not observable.
|
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -12,7 +12,6 @@ ControlParameter:
|
|
12
12
|
enabled: true
|
13
13
|
exclude:
|
14
14
|
- Mutant::Expression#match_length
|
15
|
-
- Mutant::Reporter::CLI::Printer::SubjectProgress#print_mutation_result
|
16
15
|
DataClump:
|
17
16
|
enabled: true
|
18
17
|
exclude: []
|
@@ -26,24 +25,18 @@ DuplicateMethodCall:
|
|
26
25
|
FeatureEnvy:
|
27
26
|
enabled: true
|
28
27
|
exclude:
|
29
|
-
# Nature of OptionParser :(
|
30
|
-
- Mutant::CLI#add_environment_options
|
31
28
|
- Mutant::Env#scope_name
|
32
29
|
- Mutant::Diff#minimized_hunks
|
33
|
-
- Mutant::Integration::Rspec#
|
34
|
-
- Mutant::Integration::Rspec::Rspec2#full_description
|
35
|
-
- Mutant::Integration::Rspec::Rspec3#full_description
|
30
|
+
- Mutant::Integration::Rspec#parse_example
|
36
31
|
- Mutant::Matcher::Method::Instance#match?
|
37
32
|
- Mutant::Matcher::Method::Singleton#receiver?
|
38
|
-
- Mutant::Mutation::Evil#success?
|
39
|
-
- Mutant::Mutation::Neutral#success?
|
40
33
|
- Mutant::Mutator::Node#children_indices
|
41
|
-
# False positive, its a utility
|
42
|
-
- Mutant::Meta::Example::Verification#format_mutation
|
34
|
+
- Mutant::Meta::Example::Verification#format_mutation # False positive, its a utility
|
43
35
|
- Mutant::Reporter::CLI#subject_results
|
44
|
-
- Mutant::Runner#run_mutation_test
|
45
|
-
- Mutant::Runner#kill_mutation
|
46
36
|
- Mutant::Runner#finish
|
37
|
+
- Mutant::Runner::Master#stop_worker
|
38
|
+
- Mutant::Runner::Worker#run_mutation
|
39
|
+
- Mutant::Runner::Worker#handle
|
47
40
|
IrresponsibleModule:
|
48
41
|
enabled: true
|
49
42
|
exclude: []
|
@@ -51,8 +44,6 @@ LongParameterList:
|
|
51
44
|
enabled: true
|
52
45
|
exclude:
|
53
46
|
- Mutant::Matcher::Method::Instance#self.build?
|
54
|
-
- Mutant::Runner#finish # API client of parallel, one gets _ignored.
|
55
|
-
- Mutant::Runner#self.run
|
56
47
|
max_params: 2
|
57
48
|
LongYieldList:
|
58
49
|
enabled: true
|
@@ -63,7 +54,6 @@ NestedIterators:
|
|
63
54
|
exclude:
|
64
55
|
- Mutant#self.singleton_subclass_instance
|
65
56
|
- Mutant::CLI#parse
|
66
|
-
- Mutant::Integration::Rspec#run
|
67
57
|
- Mutant::Isolation::Fork#self.call
|
68
58
|
- Mutant::Mutator::Util::Array::Element#dispatch
|
69
59
|
- Mutant::Mutator::Node::Resbody#mutate_captures
|
@@ -80,41 +70,31 @@ RepeatedConditional:
|
|
80
70
|
enabled: true
|
81
71
|
exclude:
|
82
72
|
- Mutant::Mutator
|
83
|
-
- Mutant::Reporter::CLI
|
84
73
|
- Mutant::Meta::Example::DSL
|
74
|
+
- Mutant::Runner::Master
|
85
75
|
max_ifs: 1
|
86
76
|
TooManyInstanceVariables:
|
87
77
|
enabled: true
|
88
78
|
exclude:
|
89
79
|
- Mutant::Mutator # 4 vars
|
90
|
-
- Mutant::Runner
|
80
|
+
- Mutant::Runner::Master # 4 vars
|
81
|
+
- Mutant::Runner::Scheduler # 4 vars
|
91
82
|
max_instance_variables: 3
|
92
83
|
TooManyMethods:
|
93
84
|
enabled: true
|
94
85
|
exclude:
|
95
86
|
- Mutant::CLI
|
96
|
-
- Mutant::Subject
|
97
87
|
- Mutant::Mutator::Node
|
98
|
-
- Mutant::Reporter::CLI
|
99
|
-
- Mutant::Runner
|
100
88
|
- Mutant::Meta::Example::Verification
|
101
89
|
max_methods: 10
|
102
90
|
TooManyStatements:
|
103
91
|
enabled: true
|
104
92
|
exclude:
|
105
|
-
- Mutant#self.singleton_subclass_instance
|
106
|
-
- Mutant::Integration::Rspec#run
|
107
93
|
- Mutant::Isolation::Fork#self.call
|
108
|
-
- Mutant::Reporter::CLI#colorized_diff
|
109
94
|
- Mutant::Reporter::CLI::Printer::EnvProgress#run
|
110
95
|
- Mutant::Reporter::CLI::Printer::Config#run
|
111
|
-
- Mutant::RequireHighjack#infect
|
112
|
-
- Mutant::Rspec::Killer#run
|
113
|
-
- Mutant::Runner#visit_collection
|
114
96
|
- Mutant::Runner#initialize
|
115
|
-
- Mutant::Runner::Mutation#run
|
116
97
|
- Mutant::Zombifier::File#self.find
|
117
|
-
- Mutant::CLI#add_debug_options
|
118
98
|
- Mutant::CLI#add_environment_options
|
119
99
|
max_statements: 7
|
120
100
|
UncommunicativeMethodName:
|
@@ -129,9 +109,7 @@ UncommunicativeMethodName:
|
|
129
109
|
accept: []
|
130
110
|
UncommunicativeModuleName:
|
131
111
|
enabled: true
|
132
|
-
exclude:
|
133
|
-
- Rspec2
|
134
|
-
- Rspec3
|
112
|
+
exclude: []
|
135
113
|
reject:
|
136
114
|
- !ruby/regexp /^.$/
|
137
115
|
- !ruby/regexp /[0-9]$/
|
@@ -160,14 +138,7 @@ UtilityFunction:
|
|
160
138
|
exclude:
|
161
139
|
- Mutant::AST::Sexp#s
|
162
140
|
- Mutant::CLI#reporter
|
163
|
-
- Mutant::Integration::Rspec#
|
164
|
-
- Mutant::
|
165
|
-
- Mutant::Integration::Rspec::Rspec2#full_description
|
166
|
-
- Mutant::Integration::Rspec::Rspec2#new_reporter
|
167
|
-
- Mutant::Integration::Rspec::Rspec3#full_description
|
168
|
-
- Mutant::Meta::Example::Verification#format_mutation
|
169
|
-
- Mutant::Mutation::Evil#success?
|
170
|
-
- Mutant::Mutation::Neutral#success?
|
141
|
+
- Mutant::Integration::Rspec#parse_example
|
142
|
+
- Mutant::Meta::Example::Verification#format_mutation # False positive, its a utility
|
171
143
|
- Mutant::Reporter::CLI::Format::Progressive#new_buffer
|
172
|
-
- Mutant::Runner#run_mutation_test
|
173
144
|
max_helper_calls: 0
|
data/config/rubocop.yml
CHANGED
@@ -3,7 +3,7 @@ inherit_from: ../.rubocop.yml
|
|
3
3
|
# General note about rubocop.
|
4
4
|
# It does NOT allow to silence a specific rule violation.
|
5
5
|
# For that reason I sometimes have to disable a whole cop where
|
6
|
-
# I just tried to whitelist a specific
|
6
|
+
# I just tried to whitelist a specific occurrence.
|
7
7
|
|
8
8
|
|
9
9
|
AllCops:
|
data/lib/mutant.rb
CHANGED
@@ -100,10 +100,15 @@ require 'mutant/ast/nodes'
|
|
100
100
|
require 'mutant/ast/named_children'
|
101
101
|
require 'mutant/ast/node_predicates'
|
102
102
|
require 'mutant/ast/meta'
|
103
|
+
require 'mutant/actor'
|
104
|
+
require 'mutant/actor/receiver'
|
105
|
+
require 'mutant/actor/sender'
|
106
|
+
require 'mutant/actor/mailbox'
|
107
|
+
require 'mutant/actor/actor'
|
108
|
+
require 'mutant/actor/env'
|
103
109
|
require 'mutant/cache'
|
104
110
|
require 'mutant/delegator'
|
105
111
|
require 'mutant/warning_filter'
|
106
|
-
require 'mutant/warning_expectation'
|
107
112
|
require 'mutant/require_highjack'
|
108
113
|
require 'mutant/isolation'
|
109
114
|
require 'mutant/mutator'
|
@@ -196,7 +201,9 @@ require 'mutant/cli'
|
|
196
201
|
require 'mutant/color'
|
197
202
|
require 'mutant/diff'
|
198
203
|
require 'mutant/runner'
|
199
|
-
require 'mutant/runner/
|
204
|
+
require 'mutant/runner/scheduler'
|
205
|
+
require 'mutant/runner/master'
|
206
|
+
require 'mutant/runner/worker'
|
200
207
|
require 'mutant/result'
|
201
208
|
require 'mutant/reporter'
|
202
209
|
require 'mutant/reporter/null'
|
@@ -224,6 +231,7 @@ module Mutant
|
|
224
231
|
reporter: Reporter::CLI.build($stdout),
|
225
232
|
zombie: false,
|
226
233
|
jobs: Mutant.ci? ? CI_DEFAULT_PROCESSOR_COUNT : Parallel.processor_count,
|
234
|
+
actor_env: Mutant::Actor::Env.new(Thread),
|
227
235
|
expected_coverage: 100.0
|
228
236
|
)
|
229
237
|
end # Config
|
data/lib/mutant/actor.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Mutant
|
2
|
+
# A minimal actor implementation
|
3
|
+
module Actor
|
4
|
+
|
5
|
+
# Error raised when actor signalling protocol is violated
|
6
|
+
class ProtocolError < RuntimeError
|
7
|
+
end # ProtocolError
|
8
|
+
|
9
|
+
# Undefined message payload
|
10
|
+
Undefined = Class.new do
|
11
|
+
INSPECT = 'Mutant::Actor::Undefined'.freeze
|
12
|
+
|
13
|
+
# Return object inspection
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def inspect
|
20
|
+
INSPECT
|
21
|
+
end
|
22
|
+
end.new
|
23
|
+
|
24
|
+
# Message being exchanged between actors
|
25
|
+
class Message
|
26
|
+
include Concord::Public.new(:type, :payload)
|
27
|
+
|
28
|
+
# Return new message
|
29
|
+
#
|
30
|
+
# @param [Symbol] type
|
31
|
+
# @param [Object] payload
|
32
|
+
#
|
33
|
+
# @return [Message]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
def self.new(_type, _payload = Undefined)
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
end # Message
|
42
|
+
|
43
|
+
# Bindin to others actors sender for simple RPC
|
44
|
+
class Binding
|
45
|
+
include Concord.new(:actor, :other)
|
46
|
+
|
47
|
+
# Send message and wait for reply
|
48
|
+
#
|
49
|
+
# @param [Symbol] type
|
50
|
+
#
|
51
|
+
# @return [Object]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
#
|
55
|
+
def call(type)
|
56
|
+
other.call(Message.new(type, actor.sender))
|
57
|
+
message = actor.receiver.call
|
58
|
+
fail ProtocolError, "Expected #{type} but got #{message.type}" unless type.equal?(message.type)
|
59
|
+
message.payload
|
60
|
+
end
|
61
|
+
|
62
|
+
end # Binding
|
63
|
+
end # Actor
|
64
|
+
end # Mutant
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Mutant
|
2
|
+
module Actor
|
3
|
+
# Actor object available to acting threads
|
4
|
+
class Actor
|
5
|
+
include Concord.new(:thread, :mailbox)
|
6
|
+
|
7
|
+
# Initialize object
|
8
|
+
#
|
9
|
+
# @return [undefined]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
def initialize(*)
|
14
|
+
super
|
15
|
+
@sender = mailbox.sender(thread)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return sender to this actor
|
19
|
+
#
|
20
|
+
# @return [Sender]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
attr_reader :sender
|
25
|
+
|
26
|
+
# Return receiver for messages to this actor
|
27
|
+
#
|
28
|
+
# @return [Receiver]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
def receiver
|
33
|
+
mailbox.receiver
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return binding for RPC to other actors
|
37
|
+
#
|
38
|
+
# @param [Actor::Sender] other
|
39
|
+
#
|
40
|
+
# @return [Binding]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def bind(other)
|
45
|
+
Binding.new(self, other)
|
46
|
+
end
|
47
|
+
|
48
|
+
end # Actor
|
49
|
+
end # Actor
|
50
|
+
end # Mutant
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Mutant
|
2
|
+
module Actor
|
3
|
+
# Actor root environment
|
4
|
+
class Env
|
5
|
+
include Concord.new(:thread_root)
|
6
|
+
|
7
|
+
# Spawn a new actor executing block
|
8
|
+
#
|
9
|
+
# @return [Actor::Sender]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
def spawn
|
14
|
+
mailbox = Mailbox.new
|
15
|
+
|
16
|
+
thread = thread_root.new do
|
17
|
+
yield mailbox.actor(thread_root.current)
|
18
|
+
end
|
19
|
+
|
20
|
+
mailbox.sender(thread)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return an private actor for current thread
|
24
|
+
#
|
25
|
+
# @return [Actor::Private]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def current
|
30
|
+
Mailbox.new.actor(thread_root.current)
|
31
|
+
end
|
32
|
+
|
33
|
+
end # Env
|
34
|
+
end # Actor
|
35
|
+
end # Mutant
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Mutant
|
2
|
+
module Actor
|
3
|
+
# Unbound mailbox
|
4
|
+
class Mailbox
|
5
|
+
|
6
|
+
# Initialize new unbound mailbox
|
7
|
+
#
|
8
|
+
# @return [undefined]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
def initialize
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@messages = []
|
15
|
+
@receiver = Receiver.new(@mutex, @messages)
|
16
|
+
freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return receiver
|
20
|
+
#
|
21
|
+
# @return [Receiver]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
#
|
25
|
+
attr_reader :receiver
|
26
|
+
|
27
|
+
# Return actor that is able to read mailbox
|
28
|
+
#
|
29
|
+
# @param [Thread] thread
|
30
|
+
#
|
31
|
+
# @return [Actor]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
def actor(thread)
|
36
|
+
Actor.new(thread, self)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return sender to mailbox
|
40
|
+
#
|
41
|
+
# @param [Thread] thread
|
42
|
+
#
|
43
|
+
# @return [Sender]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
def sender(thread)
|
48
|
+
Sender.new(thread, @mutex, @messages)
|
49
|
+
end
|
50
|
+
|
51
|
+
end # Mailbox
|
52
|
+
end # Actor
|
53
|
+
end # Mutant
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Mutant
|
2
|
+
module Actor
|
3
|
+
# Receiver side of an actor
|
4
|
+
class Receiver
|
5
|
+
include Concord.new(:mutex, :mailbox)
|
6
|
+
|
7
|
+
# Receives a message, blocking
|
8
|
+
#
|
9
|
+
# @return [Object]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
def call
|
14
|
+
2.times do
|
15
|
+
message = try_blocking_receive
|
16
|
+
return message unless message.equal?(Undefined)
|
17
|
+
end
|
18
|
+
fail ProtocolError
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Try a blocking receive
|
24
|
+
#
|
25
|
+
# @return [Undefined]
|
26
|
+
# if there is no message yet
|
27
|
+
#
|
28
|
+
# @return [Object]
|
29
|
+
# if there is a message
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
#
|
33
|
+
def try_blocking_receive
|
34
|
+
mutex.lock
|
35
|
+
if mailbox.empty?
|
36
|
+
mutex.unlock
|
37
|
+
Thread.stop
|
38
|
+
Undefined
|
39
|
+
else
|
40
|
+
mailbox.shift.tap do
|
41
|
+
mutex.unlock
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end # Receiver
|
47
|
+
end # Actor
|
48
|
+
end # Mutant
|