mutant 0.8.24 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/Changelog.md +14 -654
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +59 -64
  6. data/LICENSE +271 -20
  7. data/README.md +73 -140
  8. data/Rakefile +0 -21
  9. data/bin/mutant +7 -2
  10. data/config/reek.yml +2 -1
  11. data/config/rubocop.yml +5 -9
  12. data/docs/incremental.md +76 -0
  13. data/docs/known-problems.md +0 -14
  14. data/docs/mutant-minitest.md +1 -1
  15. data/docs/mutant-rspec.md +2 -24
  16. data/lib/mutant.rb +45 -53
  17. data/lib/mutant/ast/nodes.rb +0 -2
  18. data/lib/mutant/ast/types.rb +1 -117
  19. data/lib/mutant/base.rb +192 -0
  20. data/lib/mutant/bootstrap.rb +145 -0
  21. data/lib/mutant/cli.rb +68 -54
  22. data/lib/mutant/config.rb +119 -6
  23. data/lib/mutant/env.rb +94 -8
  24. data/lib/mutant/expression.rb +6 -1
  25. data/lib/mutant/expression/parser.rb +9 -31
  26. data/lib/mutant/integration.rb +64 -36
  27. data/lib/mutant/isolation.rb +16 -1
  28. data/lib/mutant/isolation/fork.rb +105 -40
  29. data/lib/mutant/license.rb +34 -0
  30. data/lib/mutant/license/subscription.rb +47 -0
  31. data/lib/mutant/license/subscription/commercial.rb +57 -0
  32. data/lib/mutant/license/subscription/opensource.rb +77 -0
  33. data/lib/mutant/loader.rb +27 -4
  34. data/lib/mutant/matcher.rb +48 -1
  35. data/lib/mutant/matcher/chain.rb +1 -1
  36. data/lib/mutant/matcher/config.rb +0 -2
  37. data/lib/mutant/matcher/filter.rb +1 -1
  38. data/lib/mutant/matcher/method.rb +11 -7
  39. data/lib/mutant/matcher/methods.rb +1 -1
  40. data/lib/mutant/matcher/namespace.rb +1 -1
  41. data/lib/mutant/matcher/null.rb +1 -1
  42. data/lib/mutant/matcher/scope.rb +1 -1
  43. data/lib/mutant/meta/example/dsl.rb +0 -8
  44. data/lib/mutant/mutation.rb +1 -2
  45. data/lib/mutant/mutator/node.rb +2 -9
  46. data/lib/mutant/mutator/node/arguments.rb +1 -1
  47. data/lib/mutant/mutator/node/class.rb +0 -8
  48. data/lib/mutant/mutator/node/define.rb +0 -12
  49. data/lib/mutant/mutator/node/generic.rb +30 -44
  50. data/lib/mutant/mutator/node/index.rb +4 -4
  51. data/lib/mutant/mutator/node/literal/regex.rb +0 -39
  52. data/lib/mutant/mutator/node/send.rb +13 -12
  53. data/lib/mutant/parallel.rb +61 -40
  54. data/lib/mutant/parallel/driver.rb +59 -0
  55. data/lib/mutant/parallel/source.rb +6 -2
  56. data/lib/mutant/parallel/worker.rb +63 -45
  57. data/lib/mutant/range.rb +15 -0
  58. data/lib/mutant/reporter/cli.rb +5 -11
  59. data/lib/mutant/reporter/cli/format.rb +3 -46
  60. data/lib/mutant/reporter/cli/printer/config.rb +5 -6
  61. data/lib/mutant/reporter/cli/printer/env.rb +40 -0
  62. data/lib/mutant/reporter/cli/printer/env_progress.rb +13 -17
  63. data/lib/mutant/reporter/cli/printer/isolation_result.rb +17 -3
  64. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -3
  65. data/lib/mutant/reporter/cli/printer/status_progressive.rb +19 -10
  66. data/lib/mutant/repository.rb +0 -65
  67. data/lib/mutant/repository/diff.rb +104 -0
  68. data/lib/mutant/repository/diff/ranges.rb +52 -0
  69. data/lib/mutant/result.rb +16 -7
  70. data/lib/mutant/runner.rb +38 -47
  71. data/lib/mutant/runner/sink.rb +1 -1
  72. data/lib/mutant/selector/null.rb +19 -0
  73. data/lib/mutant/subject.rb +3 -1
  74. data/lib/mutant/subject/method/instance.rb +3 -1
  75. data/lib/mutant/transform.rb +511 -0
  76. data/lib/mutant/variable.rb +282 -0
  77. data/lib/mutant/version.rb +1 -1
  78. data/lib/mutant/warnings.rb +113 -0
  79. data/meta/case.rb +1 -0
  80. data/meta/class.rb +0 -9
  81. data/meta/def.rb +1 -26
  82. data/meta/regexp.rb +10 -20
  83. data/meta/send.rb +14 -46
  84. data/mutant-minitest.gemspec +1 -1
  85. data/mutant-rspec.gemspec +2 -2
  86. data/mutant.gemspec +15 -16
  87. data/mutant.yml +6 -0
  88. data/spec/integration/mutant/isolation/fork_spec.rb +22 -5
  89. data/spec/integration/mutant/minitest_spec.rb +3 -2
  90. data/spec/integration/mutant/rspec_spec.rb +4 -3
  91. data/spec/integrations.yml +16 -13
  92. data/spec/shared/base_behavior.rb +45 -0
  93. data/spec/shared/framework_integration_behavior.rb +43 -14
  94. data/spec/spec_helper.rb +21 -17
  95. data/spec/support/corpus.rb +56 -95
  96. data/spec/support/shared_context.rb +37 -14
  97. data/spec/support/xspec.rb +7 -3
  98. data/spec/unit/mutant/bootstrap_spec.rb +216 -0
  99. data/spec/unit/mutant/cli_spec.rb +173 -117
  100. data/spec/unit/mutant/config_spec.rb +126 -0
  101. data/spec/unit/mutant/either_spec.rb +247 -0
  102. data/spec/unit/mutant/env_spec.rb +162 -40
  103. data/spec/unit/mutant/expression/method_spec.rb +16 -0
  104. data/spec/unit/mutant/expression/parser_spec.rb +29 -33
  105. data/spec/unit/mutant/expression_spec.rb +5 -7
  106. data/spec/unit/mutant/integration_spec.rb +100 -9
  107. data/spec/unit/mutant/isolation/fork_spec.rb +125 -67
  108. data/spec/unit/mutant/isolation/result_spec.rb +33 -1
  109. data/spec/unit/mutant/license_spec.rb +257 -0
  110. data/spec/unit/mutant/loader_spec.rb +50 -11
  111. data/spec/unit/mutant/matcher/compiler_spec.rb +0 -78
  112. data/spec/unit/mutant/matcher/method/instance_spec.rb +55 -11
  113. data/spec/unit/mutant/matcher/method/singleton_spec.rb +12 -2
  114. data/spec/unit/mutant/matcher_spec.rb +102 -0
  115. data/spec/unit/mutant/maybe_spec.rb +60 -0
  116. data/spec/unit/mutant/meta/example/dsl_spec.rb +1 -17
  117. data/spec/unit/mutant/mutation_spec.rb +13 -6
  118. data/spec/unit/mutant/parallel/driver_spec.rb +112 -14
  119. data/spec/unit/mutant/parallel/source/array_spec.rb +25 -17
  120. data/spec/unit/mutant/parallel/worker_spec.rb +182 -44
  121. data/spec/unit/mutant/parallel_spec.rb +105 -8
  122. data/spec/unit/mutant/range_spec.rb +141 -0
  123. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +7 -21
  124. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +15 -6
  125. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +10 -2
  126. data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +12 -4
  127. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +31 -2
  128. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +4 -4
  129. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +5 -0
  130. data/spec/unit/mutant/reporter/cli_spec.rb +46 -123
  131. data/spec/unit/mutant/repository/diff/ranges_spec.rb +180 -0
  132. data/spec/unit/mutant/repository/diff_spec.rb +84 -71
  133. data/spec/unit/mutant/require_highjack_spec.rb +1 -1
  134. data/spec/unit/mutant/result/env_spec.rb +39 -9
  135. data/spec/unit/mutant/result/test_spec.rb +14 -0
  136. data/spec/unit/mutant/runner_spec.rb +88 -41
  137. data/spec/unit/mutant/selector/expression_spec.rb +11 -10
  138. data/spec/unit/mutant/selector/null_spec.rb +17 -0
  139. data/spec/unit/mutant/subject/method/instance_spec.rb +44 -5
  140. data/spec/unit/mutant/subject/method/singleton_spec.rb +9 -2
  141. data/spec/unit/mutant/subject_spec.rb +9 -1
  142. data/spec/unit/mutant/transform/array_spec.rb +92 -0
  143. data/spec/unit/mutant/transform/bool_spec.rb +63 -0
  144. data/spec/unit/mutant/transform/error_spec.rb +132 -0
  145. data/spec/unit/mutant/transform/exception_spec.rb +44 -0
  146. data/spec/unit/mutant/transform/hash_spec.rb +236 -0
  147. data/spec/unit/mutant/transform/index_spec.rb +92 -0
  148. data/spec/unit/mutant/transform/named_spec.rb +49 -0
  149. data/spec/unit/mutant/transform/primitive_spec.rb +56 -0
  150. data/spec/unit/mutant/transform/sequence_spec.rb +98 -0
  151. data/spec/unit/mutant/variable_spec.rb +618 -0
  152. data/spec/unit/mutant/warnings_spec.rb +89 -0
  153. data/spec/unit/mutant/world_spec.rb +63 -0
  154. data/test_app/Gemfile.minitest +0 -2
  155. metadata +79 -113
  156. data/.gitattributes +0 -1
  157. data/.ruby-gemset +0 -1
  158. data/config/triage.yml +0 -2
  159. data/lib/mutant/actor.rb +0 -57
  160. data/lib/mutant/actor/env.rb +0 -31
  161. data/lib/mutant/actor/mailbox.rb +0 -34
  162. data/lib/mutant/actor/receiver.rb +0 -42
  163. data/lib/mutant/actor/sender.rb +0 -26
  164. data/lib/mutant/ast/meta/restarg.rb +0 -19
  165. data/lib/mutant/ast/regexp.rb +0 -42
  166. data/lib/mutant/ast/regexp/transformer.rb +0 -187
  167. data/lib/mutant/ast/regexp/transformer/direct.rb +0 -123
  168. data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -59
  169. data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -83
  170. data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -114
  171. data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -58
  172. data/lib/mutant/ast/regexp/transformer/root.rb +0 -31
  173. data/lib/mutant/ast/regexp/transformer/text.rb +0 -60
  174. data/lib/mutant/env/bootstrap.rb +0 -160
  175. data/lib/mutant/matcher/compiler.rb +0 -60
  176. data/lib/mutant/mutator/node/regexp.rb +0 -35
  177. data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -23
  178. data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -28
  179. data/lib/mutant/mutator/node/regexp/character_type.rb +0 -32
  180. data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -23
  181. data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -23
  182. data/lib/mutant/mutator/node/regexp/greedy_zero_or_more.rb +0 -27
  183. data/lib/mutant/parallel/master.rb +0 -181
  184. data/lib/mutant/reporter/cli/printer/status.rb +0 -53
  185. data/lib/mutant/reporter/cli/tput.rb +0 -46
  186. data/lib/mutant/warning_filter.rb +0 -61
  187. data/meta/regexp/character_types.rb +0 -23
  188. data/meta/regexp/regexp_alternation_meta.rb +0 -13
  189. data/meta/regexp/regexp_bol_anchor.rb +0 -10
  190. data/meta/regexp/regexp_bos_anchor.rb +0 -18
  191. data/meta/regexp/regexp_capture_group.rb +0 -19
  192. data/meta/regexp/regexp_eol_anchor.rb +0 -10
  193. data/meta/regexp/regexp_eos_anchor.rb +0 -8
  194. data/meta/regexp/regexp_eos_ob_eol_anchor.rb +0 -10
  195. data/meta/regexp/regexp_greedy_zero_or_more.rb +0 -12
  196. data/meta/regexp/regexp_root_expression.rb +0 -10
  197. data/meta/restarg.rb +0 -10
  198. data/spec/support/fake_actor.rb +0 -111
  199. data/spec/support/warning.rb +0 -66
  200. data/spec/unit/mutant/actor/binding_spec.rb +0 -34
  201. data/spec/unit/mutant/actor/env_spec.rb +0 -31
  202. data/spec/unit/mutant/actor/mailbox_spec.rb +0 -28
  203. data/spec/unit/mutant/actor/message_spec.rb +0 -25
  204. data/spec/unit/mutant/actor/receiver_spec.rb +0 -58
  205. data/spec/unit/mutant/actor/sender_spec.rb +0 -24
  206. data/spec/unit/mutant/ast/regexp/parse_spec.rb +0 -19
  207. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +0 -21
  208. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +0 -35
  209. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +0 -21
  210. data/spec/unit/mutant/ast/regexp_spec.rb +0 -704
  211. data/spec/unit/mutant/env/bootstrap_spec.rb +0 -188
  212. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +0 -26
  213. data/spec/unit/mutant/parallel/master_spec.rb +0 -338
  214. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -121
  215. data/spec/unit/mutant/reporter/cli/tput_spec.rb +0 -50
  216. data/spec/unit/mutant/warning_filter_spec.rb +0 -106
  217. data/spec/unit/mutant_spec.rb +0 -17
  218. data/test_app/Gemfile.rspec3.7 +0 -7
@@ -20,7 +20,7 @@ module Mutant
20
20
 
21
21
  # Matched subjects
22
22
  #
23
- # @param [Env::Bootstrap] env
23
+ # @param [Env] env
24
24
  #
25
25
  # @return [Enumerable<Subject>]
26
26
  def call(env)
@@ -80,14 +80,6 @@ module Mutant
80
80
  mutation('self')
81
81
  end
82
82
 
83
- # Add regexp mutations
84
- #
85
- # @return [undefined]
86
- def regexp_mutations
87
- mutation('//')
88
- mutation('/nomatch\A/')
89
- end
90
-
91
83
  # Helper method to coerce input to node
92
84
  #
93
85
  # @param [String,Parser::AST::Node] input
@@ -61,7 +61,7 @@ module Mutant
61
61
  #
62
62
  # @param kernel [Kernel]
63
63
  #
64
- # @return [self]
64
+ # @return [Loader::Result]
65
65
  def insert(kernel)
66
66
  subject.prepare
67
67
  Loader.call(
@@ -70,7 +70,6 @@ module Mutant
70
70
  source: monkeypatch,
71
71
  subject: subject
72
72
  )
73
- self
74
73
  end
75
74
 
76
75
  private
@@ -44,13 +44,6 @@ module Mutant
44
44
  # @return [Parser::AST::Node]
45
45
  alias_method :dup_node, :dup_input
46
46
 
47
- # Original nodes children
48
- #
49
- # @return [Array<Parser::AST::Node>]
50
- def children
51
- node.children
52
- end
53
-
54
47
  # Dispatch on child index
55
48
  #
56
49
  # @param [Integer] index
@@ -122,7 +115,7 @@ module Mutant
122
115
  #
123
116
  # @return [undefined]
124
117
  def emit_nil
125
- emit(N_NIL) unless asgn_left?
118
+ emit(N_NIL) unless left_assignment?
126
119
  end
127
120
 
128
121
  # Parent node
@@ -150,7 +143,7 @@ module Mutant
150
143
  # Test if the node is the left of an or_asgn or op_asgn
151
144
  #
152
145
  # @return [Boolean]
153
- def asgn_left?
146
+ def left_assignment?
154
147
  AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
155
148
  end
156
149
 
@@ -78,7 +78,7 @@ module Mutant
78
78
  #
79
79
  # @return [Enumerable<Parser::AST::Node, Integer>]
80
80
  def mlhs_childs_with_index
81
- children.each_with_index.select do |child, _index|
81
+ children.each_with_index.select do |child,|
82
82
  n_mlhs?(child)
83
83
  end
84
84
  end
@@ -15,16 +15,8 @@ module Mutant
15
15
  #
16
16
  # @return [undefined]
17
17
  def dispatch
18
- mutate_type
19
18
  emit_body_mutations if body
20
19
  end
21
-
22
- # Emit class -> type mutations
23
- #
24
- # @return [undefined]
25
- def mutate_type
26
- emit(s(:module, klass, body))
27
- end
28
20
  end # Class
29
21
  end # Node
30
22
  end # Mutator
@@ -14,7 +14,6 @@ module Mutant
14
14
  def dispatch
15
15
  emit_arguments_mutations
16
16
  emit_optarg_body_assignments
17
- emit_restarg_body_mutation
18
17
  emit_body(N_RAISE)
19
18
  emit_body(N_ZSUPER)
20
19
  emit_body(nil)
@@ -32,17 +31,6 @@ module Mutant
32
31
  end
33
32
  end
34
33
 
35
- # Emit mutation with arg splat as empty array assignment in method
36
- #
37
- # @return [undefined]
38
- def emit_restarg_body_mutation
39
- arguments.children.each do |argument|
40
- next unless n_restarg?(argument) && argument.children.one?
41
-
42
- emit_body_prepend(s(:lvasgn, AST::Meta::Restarg.new(argument).name, s(:array)))
43
- end
44
- end
45
-
46
34
  # Emit valid body ASTs depending on instance body
47
35
  #
48
36
  # @param node [Parser::AST::Node]
@@ -8,61 +8,47 @@ module Mutant
8
8
  class Generic < self
9
9
 
10
10
  unsupported_nodes = %i[
11
- ensure
12
- redo
13
- retry
11
+ __FILE__
12
+ __LINE__
13
+ alias
14
14
  arg_expr
15
+ back_ref
15
16
  blockarg
16
- kwrestarg
17
- undef
18
- module
17
+ blockarg_expr
18
+ complex
19
+ eflipflop
19
20
  empty
20
- alias
21
+ ensure
21
22
  for
22
- xstr
23
- back_ref
24
- restarg
25
- sclass
26
- match_with_lvasgn
27
- while_post
28
- until_post
29
- preexe
30
- postexe
23
+ ident
31
24
  iflipflop
32
- eflipflop
25
+ kwrestarg
33
26
  kwsplat
34
- shadowarg
27
+ match_with_lvasgn
28
+ meth_ref
29
+ module
30
+ objc_kwarg
31
+ objc_restarg
32
+ objc_varargs
33
+ postexe
34
+ preexe
35
35
  rational
36
- complex
37
- __FILE__
38
- __LINE__
39
- ]
40
-
41
- unsupported_regexp_nodes = AST::Types::REGEXP.to_a - %i[
42
- regexp_alternation_meta
43
- regexp_bol_anchor
44
- regexp_capture_group
45
- regexp_digit_type
46
- regexp_eol_anchor
47
- regexp_eos_ob_eol_anchor
48
- regexp_greedy_zero_or_more
49
- regexp_hex_type
50
- regexp_linebreak_type
51
- regexp_nondigit_type
52
- regexp_nonhex_type
53
- regexp_nonspace_type
54
- regexp_nonword_boundary_anchor
55
- regexp_nonword_type
56
- regexp_root_expression
57
- regexp_space_type
58
- regexp_word_boundary_anchor
59
- regexp_word_type
60
- regexp_xgrapheme_type
36
+ redo
37
+ restarg
38
+ restarg_expr
39
+ retry
40
+ root
41
+ sclass
42
+ shadowarg
43
+ undef
44
+ until_post
45
+ while_post
46
+ xstr
61
47
  ]
62
48
 
63
49
  # These nodes still need a dedicated mutator,
64
50
  # your contribution is that close!
65
- handle(*(unsupported_nodes + unsupported_regexp_nodes))
51
+ handle(*unsupported_nodes)
66
52
 
67
53
  private
68
54
 
@@ -30,7 +30,7 @@ module Mutant
30
30
  #
31
31
  # @return [undefined]
32
32
  def emit_send_forms
33
- return if asgn_left?
33
+ return if left_assignment?
34
34
 
35
35
  SEND_REPLACEMENTS.each do |selector|
36
36
  emit(s(:send, receiver, selector, *indices))
@@ -55,7 +55,7 @@ module Mutant
55
55
  # @return [undefined]
56
56
  def mutate_indices
57
57
  children_indices(index_range).each do |index|
58
- emit_propagation(children.fetch(index)) unless asgn_left?
58
+ emit_propagation(children.fetch(index)) unless left_assignment?
59
59
  delete_child(index)
60
60
  mutate_child(index)
61
61
  end
@@ -98,7 +98,7 @@ module Mutant
98
98
  def dispatch
99
99
  super()
100
100
 
101
- return if asgn_left?
101
+ return if left_assignment?
102
102
 
103
103
  emit_index_read
104
104
  emit(children.last)
@@ -116,7 +116,7 @@ module Mutant
116
116
  #
117
117
  # @return [Range<Integer>]
118
118
  def index_range
119
- if asgn_left?
119
+ if left_assignment?
120
120
  NO_VALUE_RANGE
121
121
  else
122
122
  REGULAR_RANGE
@@ -25,7 +25,6 @@ module Mutant
25
25
  #
26
26
  # @return [undefined]
27
27
  def dispatch
28
- mutate_body
29
28
  emit_singletons unless parent_node
30
29
  children.each_with_index do |child, index|
31
30
  mutate_child(index) unless n_str?(child)
@@ -34,44 +33,6 @@ module Mutant
34
33
  emit_type(s(:str, NULL_REGEXP_SOURCE), options)
35
34
  end
36
35
 
37
- # Mutate regexp body
38
- #
39
- # @note will only mutate parts of regexp body if the
40
- # body is composed of only strings. Regular expressions
41
- # with interpolation are skipped
42
- #
43
- # @return [undefined]
44
- def mutate_body
45
- return unless body.all?(&method(:n_str?)) && body_ast
46
-
47
- Mutator.mutate(body_ast).each do |mutation|
48
- source = AST::Regexp.to_expression(mutation).to_s
49
- emit_type(s(:str, source), options)
50
- end
51
- end
52
-
53
- # AST representation of regexp body
54
- #
55
- # @return [Parser::AST::Node, nil]
56
- def body_ast
57
- body_expression and AST::Regexp.to_ast(body_expression)
58
- end
59
-
60
- # Expression representation of regexp body
61
- #
62
- # @return [Regexp::Expression, nil]
63
- def body_expression
64
- AST::Regexp.parse(body.map(&:children).join)
65
- end
66
- memoize :body_expression
67
-
68
- # Children of regexp node which compose regular expression source
69
- #
70
- # @return [Array<Parser::AST::Node>]
71
- def body
72
- children.slice(0...-1)
73
- end
74
-
75
36
  end # Regex
76
37
  end # Literal
77
38
  end # Node
@@ -21,11 +21,6 @@ module Mutant
21
21
  reverse_merge: %i[merge],
22
22
  map: %i[each],
23
23
  flat_map: %i[map],
24
- sample: %i[first last],
25
- pop: %i[last],
26
- shift: %i[first],
27
- first: %i[last],
28
- last: %i[first],
29
24
  send: %i[public_send __send__],
30
25
  __send__: %i[public_send],
31
26
  method: %i[public_method],
@@ -33,13 +28,11 @@ module Mutant
33
28
  eql?: %i[equal?],
34
29
  to_s: %i[to_str],
35
30
  to_i: %i[to_int],
36
- to_a: %i[to_ary to_set],
31
+ to_a: %i[to_ary],
37
32
  to_h: %i[to_hash],
38
33
  at: %i[fetch key?],
39
34
  fetch: %i[key?],
40
35
  values_at: %i[fetch_values],
41
- match: %i[match?],
42
- '=~': %i[match?],
43
36
  :== => %i[eql? equal?],
44
37
  :>= => %i[> == eql? equal?],
45
38
  :<= => %i[< == eql? equal?],
@@ -159,7 +152,7 @@ module Mutant
159
152
  #
160
153
  # @return [undefined]
161
154
  def emit_integer_mutation
162
- return unless receiver && selector.equal?(:to_i)
155
+ return unless selector.equal?(:to_i)
163
156
 
164
157
  emit(s(:send, nil, :Integer, receiver))
165
158
  end
@@ -193,11 +186,20 @@ module Mutant
193
186
  def mutate_arguments
194
187
  emit_type(receiver, selector)
195
188
  remaining_children_with_index.each do |_node, index|
196
- mutate_child(index)
189
+ mutate_argument_index(index)
197
190
  delete_child(index)
198
191
  end
199
192
  end
200
193
 
194
+ # Mutate argument
195
+ #
196
+ # @param [Integer] index
197
+ #
198
+ # @return [undefined]
199
+ def mutate_argument_index(index)
200
+ mutate_child(index) { |node| !n_begin?(node) }
201
+ end
202
+
201
203
  # Emit argument propagation
202
204
  #
203
205
  # @return [undefined]
@@ -221,8 +223,7 @@ module Mutant
221
223
  # @return [undefined]
222
224
  def emit_implicit_self
223
225
  emit_receiver(nil) if n_self?(receiver) && !(
224
- KEYWORDS.include?(selector) ||
225
- METHOD_OPERATORS.include?(selector) ||
226
+ KEYWORDS.include?(selector) ||
226
227
  meta.attribute_assignment?
227
228
  )
228
229
  end
@@ -4,32 +4,65 @@ module Mutant
4
4
  # Parallel execution engine of arbitrary payloads
5
5
  module Parallel
6
6
 
7
- # Driver for parallelized execution
8
- class Driver
9
- include Concord.new(:binding)
10
-
11
- # Scheduler status
12
- #
13
- # @return [Object]
14
- def status
15
- binding.call(__method__)
16
- end
17
-
18
- # Stop master gracefully
19
- #
20
- # @return [self]
21
- def stop
22
- binding.call(__method__)
23
- self
24
- end
25
- end # Driver
26
-
27
7
  # Run async computation returning driver
28
8
  #
9
+ # @param [Config] config
10
+ #
29
11
  # @return [Driver]
30
12
  def self.async(config)
31
- Driver.new(config.env.new_mailbox.bind(Master.call(config)))
13
+ shared = {
14
+ var_active_jobs: shared(Variable::IVar, config, value: Set.new),
15
+ var_final: shared(Variable::IVar, config),
16
+ var_sink: shared(Variable::IVar, config, value: config.sink)
17
+ }
18
+
19
+ Driver.new(
20
+ threads: threads(config, worker(config, **shared)),
21
+ **shared
22
+ )
23
+ end
24
+
25
+ # The worker
26
+ #
27
+ # @param [Config] config
28
+ #
29
+ # @return [Worker]
30
+ def self.worker(config, **shared)
31
+ Worker.new(
32
+ processor: config.processor,
33
+ var_running: shared(Variable::MVar, config, value: config.jobs),
34
+ var_source: shared(Variable::IVar, config, value: config.source),
35
+ **shared
36
+ )
37
+ end
38
+
39
+ # Start threads
40
+ #
41
+ # @param [Config] config
42
+ # @param [Worker] worker
43
+ #
44
+ # @return [Array<Thread>]
45
+ def self.threads(config, worker)
46
+ Array.new(config.jobs) { config.thread.new(&worker.method(:call)) }
32
47
  end
48
+ private_class_method :threads
49
+
50
+ # Create shared variable
51
+ #
52
+ # @param [Class] klass
53
+ # @param [Config] config
54
+ #
55
+ # @return [Mutant::Variable]
56
+ #
57
+ # ignore :reek:LongParameterList
58
+ def self.shared(klass, config, **attributes)
59
+ klass.new(
60
+ condition_variable: config.condition_variable,
61
+ mutex: config.mutex,
62
+ **attributes
63
+ )
64
+ end
65
+ private_class_method :shared
33
66
 
34
67
  # Job result sink
35
68
  class Sink
@@ -42,7 +75,7 @@ module Mutant
42
75
  # @return [self]
43
76
  abstract_method :result
44
77
 
45
- # Sink status
78
+ # The sink status
46
79
  #
47
80
  # @return [Object]
48
81
  abstract_method :status
@@ -53,30 +86,16 @@ module Mutant
53
86
  abstract_method :stop?
54
87
  end # Sink
55
88
 
56
- # Job to push to workers
57
- class Job
58
- include Adamantium::Flat, Anima.new(
59
- :index,
60
- :payload
61
- )
62
- end # Job
63
-
64
- # Job result object received from workers
65
- class JobResult
66
- include Adamantium::Flat, Anima.new(
67
- :job,
68
- :payload
69
- )
70
- end # JobResult
71
-
72
89
  # Parallel run configuration
73
90
  class Config
74
91
  include Adamantium::Flat, Anima.new(
75
- :env,
92
+ :condition_variable,
76
93
  :jobs,
94
+ :mutex,
77
95
  :processor,
78
96
  :sink,
79
- :source
97
+ :source,
98
+ :thread
80
99
  )
81
100
  end # Config
82
101
 
@@ -87,6 +106,8 @@ module Mutant
87
106
  :done,
88
107
  :payload
89
108
  )
109
+
110
+ alias_method :done?, :done
90
111
  end # Status
91
112
 
92
113
  end # Parallel