mutant 0.10.20 → 0.10.25
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/lib/mutant.rb +23 -4
- data/lib/mutant/ast/meta/send.rb +0 -1
- data/lib/mutant/ast/regexp.rb +37 -0
- data/lib/mutant/ast/regexp/transformer.rb +150 -0
- data/lib/mutant/ast/regexp/transformer/direct.rb +121 -0
- data/lib/mutant/ast/regexp/transformer/named_group.rb +50 -0
- data/lib/mutant/ast/regexp/transformer/options_group.rb +68 -0
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +90 -0
- data/lib/mutant/ast/regexp/transformer/recursive.rb +56 -0
- data/lib/mutant/ast/regexp/transformer/root.rb +28 -0
- data/lib/mutant/ast/regexp/transformer/text.rb +58 -0
- data/lib/mutant/ast/types.rb +115 -11
- data/lib/mutant/cli/command/environment.rb +9 -3
- data/lib/mutant/config.rb +8 -54
- data/lib/mutant/config/coverage_criteria.rb +61 -0
- data/lib/mutant/env.rb +8 -6
- data/lib/mutant/expression.rb +0 -12
- data/lib/mutant/expression/namespace.rb +1 -1
- data/lib/mutant/isolation/fork.rb +1 -1
- data/lib/mutant/loader.rb +1 -1
- data/lib/mutant/matcher.rb +2 -2
- data/lib/mutant/matcher/config.rb +27 -6
- data/lib/mutant/matcher/method.rb +2 -3
- data/lib/mutant/matcher/method/metaclass.rb +1 -1
- data/lib/mutant/meta/example/dsl.rb +6 -1
- data/lib/mutant/mutator/node/arguments.rb +0 -2
- data/lib/mutant/mutator/node/block.rb +5 -1
- data/lib/mutant/mutator/node/dynamic_literal.rb +1 -1
- data/lib/mutant/mutator/node/kwargs.rb +44 -0
- data/lib/mutant/mutator/node/literal/regex.rb +26 -0
- data/lib/mutant/mutator/node/literal/symbol.rb +0 -2
- data/lib/mutant/mutator/node/regexp.rb +20 -0
- data/lib/mutant/mutator/node/regexp/alternation_meta.rb +20 -0
- data/lib/mutant/mutator/node/regexp/beginning_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/capture_group.rb +25 -0
- data/lib/mutant/mutator/node/regexp/character_type.rb +31 -0
- data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/zero_or_more.rb +34 -0
- data/lib/mutant/mutator/node/sclass.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +36 -19
- data/lib/mutant/parallel.rb +43 -28
- data/lib/mutant/parallel/driver.rb +9 -3
- data/lib/mutant/parallel/worker.rb +60 -2
- data/lib/mutant/pipe.rb +94 -0
- data/lib/mutant/reporter/cli/printer/env.rb +1 -1
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +1 -6
- data/lib/mutant/result.rb +8 -0
- data/lib/mutant/runner.rb +7 -10
- data/lib/mutant/runner/sink.rb +12 -2
- data/lib/mutant/subject.rb +1 -3
- data/lib/mutant/subject/method/instance.rb +2 -4
- data/lib/mutant/timer.rb +2 -4
- data/lib/mutant/transform.rb +25 -2
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/world.rb +1 -2
- metadata +48 -9
- data/lib/mutant/warnings.rb +0 -106
| @@ -19,6 +19,7 @@ module Mutant | |
| 19 19 | 
             
                      end
         | 
| 20 20 |  | 
| 21 21 | 
             
                      def dispatch
         | 
| 22 | 
            +
                        mutate_body
         | 
| 22 23 | 
             
                        emit_singletons unless parent_node
         | 
| 23 24 | 
             
                        children.each_with_index do |child, index|
         | 
| 24 25 | 
             
                          mutate_child(index) unless n_str?(child)
         | 
| @@ -27,6 +28,31 @@ module Mutant | |
| 27 28 | 
             
                        emit_type(s(:str, NULL_REGEXP_SOURCE), options)
         | 
| 28 29 | 
             
                      end
         | 
| 29 30 |  | 
| 31 | 
            +
                      # NOTE: will only mutate parts of regexp body if the
         | 
| 32 | 
            +
                      # body is composed of only strings. Regular expressions
         | 
| 33 | 
            +
                      # with interpolation are skipped
         | 
| 34 | 
            +
                      def mutate_body
         | 
| 35 | 
            +
                        return unless body.all?(&method(:n_str?))
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                        Mutator.mutate(body_ast).each do |mutation|
         | 
| 38 | 
            +
                          source = AST::Regexp.to_expression(mutation).to_s
         | 
| 39 | 
            +
                          emit_type(s(:str, source), options)
         | 
| 40 | 
            +
                        end
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                      def body_ast
         | 
| 44 | 
            +
                        AST::Regexp.to_ast(body_expression)
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                      def body_expression
         | 
| 48 | 
            +
                        AST::Regexp.parse(body.map(&:children).join)
         | 
| 49 | 
            +
                      end
         | 
| 50 | 
            +
                      memoize :body_expression
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                      def body
         | 
| 53 | 
            +
                        children.slice(0...-1)
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
             | 
| 30 56 | 
             
                    end # Regex
         | 
| 31 57 | 
             
                  end # Literal
         | 
| 32 58 | 
             
                end # Node
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for root expression regexp wrapper
         | 
| 8 | 
            +
                    class RootExpression < Node
         | 
| 9 | 
            +
                      handle(:regexp_root_expression)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      def dispatch
         | 
| 14 | 
            +
                        children.each_index(&method(:mutate_child))
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end # RootExpression
         | 
| 17 | 
            +
                  end # Regexp
         | 
| 18 | 
            +
                end # Node
         | 
| 19 | 
            +
              end # Mutator
         | 
| 20 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for pipe in `/foo|bar/` regexp
         | 
| 8 | 
            +
                    class AlternationMeta < Node
         | 
| 9 | 
            +
                      handle(:regexp_alternation_meta)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      def dispatch
         | 
| 14 | 
            +
                        children.each_index(&method(:delete_child))
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end # AlternationMeta
         | 
| 17 | 
            +
                  end # Regexp
         | 
| 18 | 
            +
                end # Node
         | 
| 19 | 
            +
              end # Mutator
         | 
| 20 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for beginning of line anchor `^`
         | 
| 8 | 
            +
                    class BeginningOfLineAnchor < Node
         | 
| 9 | 
            +
                      handle(:regexp_bol_anchor)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                      private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      def dispatch
         | 
| 14 | 
            +
                        emit(s(:regexp_bos_anchor))
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end # BeginningOfLineAnchor
         | 
| 17 | 
            +
                  end # Regexp
         | 
| 18 | 
            +
                end # Node
         | 
| 19 | 
            +
              end # Mutator
         | 
| 20 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for regexp capture groups, such as `/(foo)/`
         | 
| 8 | 
            +
                    class CaptureGroup < Node
         | 
| 9 | 
            +
                      handle(:regexp_capture_group)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                      children :group
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    private
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                      def dispatch
         | 
| 16 | 
            +
                        return unless group
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                        emit(s(:regexp_passive_group, group))
         | 
| 19 | 
            +
                        emit_group_mutations
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
                    end # EndOfLineAnchor
         | 
| 22 | 
            +
                  end # Regexp
         | 
| 23 | 
            +
                end # Node
         | 
| 24 | 
            +
              end # Mutator
         | 
| 25 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Character type mutator
         | 
| 8 | 
            +
                    class CharacterType < Node
         | 
| 9 | 
            +
                      map = {
         | 
| 10 | 
            +
                        regexp_digit_type:           :regexp_nondigit_type,
         | 
| 11 | 
            +
                        regexp_hex_type:             :regexp_nonhex_type,
         | 
| 12 | 
            +
                        regexp_space_type:           :regexp_nonspace_type,
         | 
| 13 | 
            +
                        regexp_word_boundary_anchor: :regexp_nonword_boundary_anchor,
         | 
| 14 | 
            +
                        regexp_word_type:            :regexp_nonword_type,
         | 
| 15 | 
            +
                        regexp_xgrapheme_type:       :regexp_linebreak_type
         | 
| 16 | 
            +
                      }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      MAP = IceNine.deep_freeze(map.merge(map.invert))
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                      handle(*MAP.keys)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      def dispatch
         | 
| 25 | 
            +
                        emit(s(MAP.fetch(node.type)))
         | 
| 26 | 
            +
                      end
         | 
| 27 | 
            +
                    end # CharacterType
         | 
| 28 | 
            +
                  end # Regexp
         | 
| 29 | 
            +
                end # Node
         | 
| 30 | 
            +
              end # Mutator
         | 
| 31 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for end of line anchor `$`
         | 
| 8 | 
            +
                    class EndOfLineAnchor < Node
         | 
| 9 | 
            +
                      handle(:regexp_eol_anchor)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      def dispatch
         | 
| 14 | 
            +
                        emit(s(:regexp_eos_anchor))
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end # EndOfLineAnchor
         | 
| 17 | 
            +
                  end # Regexp
         | 
| 18 | 
            +
                end # Node
         | 
| 19 | 
            +
              end # Mutator
         | 
| 20 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for end of line or before end of string anchor `\Z`
         | 
| 8 | 
            +
                    class EndOfStringOrBeforeEndOfLineAnchor < Node
         | 
| 9 | 
            +
                      handle(:regexp_eos_ob_eol_anchor)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                      def dispatch
         | 
| 14 | 
            +
                        emit(s(:regexp_eos_anchor))
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end # EndOfStringOrBeforeEndOfLineAnchor
         | 
| 17 | 
            +
                  end # Regexp
         | 
| 18 | 
            +
                end # Node
         | 
| 19 | 
            +
              end # Mutator
         | 
| 20 | 
            +
            end # Mutant
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Mutant
         | 
| 4 | 
            +
              class Mutator
         | 
| 5 | 
            +
                class Node
         | 
| 6 | 
            +
                  module Regexp
         | 
| 7 | 
            +
                    # Mutator for zero-or-more quantifier, `*`
         | 
| 8 | 
            +
                    class ZeroOrMore < Node
         | 
| 9 | 
            +
                      MAP = IceNine.deep_freeze(
         | 
| 10 | 
            +
                        regexp_greedy_zero_or_more:     :regexp_greedy_one_or_more,
         | 
| 11 | 
            +
                        regexp_reluctant_zero_or_more:  :regexp_reluctant_one_or_more,
         | 
| 12 | 
            +
                        regexp_possessive_zero_or_more: :regexp_possessive_one_or_more
         | 
| 13 | 
            +
                      )
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                      handle(*MAP.keys)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      children :min, :max, :subject
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                      # Replace:
         | 
| 22 | 
            +
                      # * `/a*/`  with `/a+/`
         | 
| 23 | 
            +
                      # * `/a*?/` with `/a+?/`
         | 
| 24 | 
            +
                      # * `/a*+/` with `/a++/`
         | 
| 25 | 
            +
                      def dispatch
         | 
| 26 | 
            +
                        emit(s(MAP.fetch(node.type), *children))
         | 
| 27 | 
            +
                        emit_subject_mutations
         | 
| 28 | 
            +
                        emit(subject)
         | 
| 29 | 
            +
                      end
         | 
| 30 | 
            +
                    end # ZeroOrMore
         | 
| 31 | 
            +
                  end # Regexp
         | 
| 32 | 
            +
                end # Node
         | 
| 33 | 
            +
              end # Mutator
         | 
| 34 | 
            +
            end # Mutant
         | 
| @@ -14,30 +14,35 @@ module Mutant | |
| 14 14 | 
             
                    children :receiver, :selector
         | 
| 15 15 |  | 
| 16 16 | 
             
                    SELECTOR_REPLACEMENTS = IceNine.deep_freeze(
         | 
| 17 | 
            -
                       | 
| 18 | 
            -
                       | 
| 17 | 
            +
                      :< =>          %i[== eql? equal?],
         | 
| 18 | 
            +
                      :<= =>         %i[< == eql? equal?],
         | 
| 19 | 
            +
                      :== =>         %i[eql? equal?],
         | 
| 20 | 
            +
                      :=== =>        %i[is_a?],
         | 
| 21 | 
            +
                      :=~ =>         %i[match?],
         | 
| 22 | 
            +
                      :> =>          %i[== eql? equal?],
         | 
| 23 | 
            +
                      :>= =>         %i[> == eql? equal?],
         | 
| 24 | 
            +
                      __send__:      %i[public_send],
         | 
| 25 | 
            +
                      all?:          %i[any?],
         | 
| 26 | 
            +
                      any?:          %i[all?],
         | 
| 27 | 
            +
                      at:            %i[fetch key?],
         | 
| 28 | 
            +
                      eql?:          %i[equal?],
         | 
| 29 | 
            +
                      fetch:         %i[key?],
         | 
| 30 | 
            +
                      flat_map:      %i[map],
         | 
| 31 | 
            +
                      gsub:          %i[sub],
         | 
| 19 32 | 
             
                      is_a?:         %i[instance_of?],
         | 
| 33 | 
            +
                      kind_of?:      %i[instance_of?],
         | 
| 34 | 
            +
                      map:           %i[each],
         | 
| 35 | 
            +
                      method:        %i[public_method],
         | 
| 36 | 
            +
                      match:         %i[match?],
         | 
| 20 37 | 
             
                      reverse_each:  %i[each],
         | 
| 38 | 
            +
                      reverse_map:   %i[map each],
         | 
| 21 39 | 
             
                      reverse_merge: %i[merge],
         | 
| 22 | 
            -
                      map:           %i[each],
         | 
| 23 | 
            -
                      flat_map:      %i[map],
         | 
| 24 40 | 
             
                      send:          %i[public_send __send__],
         | 
| 25 | 
            -
                      __send__:      %i[public_send],
         | 
| 26 | 
            -
                      method:        %i[public_method],
         | 
| 27 | 
            -
                      gsub:          %i[sub],
         | 
| 28 | 
            -
                      eql?:          %i[equal?],
         | 
| 29 | 
            -
                      to_s:          %i[to_str],
         | 
| 30 | 
            -
                      to_i:          %i[to_int],
         | 
| 31 41 | 
             
                      to_a:          %i[to_ary],
         | 
| 32 42 | 
             
                      to_h:          %i[to_hash],
         | 
| 33 | 
            -
                       | 
| 34 | 
            -
                       | 
| 35 | 
            -
                      values_at:     %i[fetch_values] | 
| 36 | 
            -
                      :== =>         %i[eql? equal?],
         | 
| 37 | 
            -
                      :>= =>         %i[> == eql? equal?],
         | 
| 38 | 
            -
                      :<= =>         %i[< == eql? equal?],
         | 
| 39 | 
            -
                      :> =>          %i[== eql? equal?],
         | 
| 40 | 
            -
                      :< =>          %i[== eql? equal?]
         | 
| 43 | 
            +
                      to_i:          %i[to_int],
         | 
| 44 | 
            +
                      to_s:          %i[to_str],
         | 
| 45 | 
            +
                      values_at:     %i[fetch_values]
         | 
| 41 46 | 
             
                    )
         | 
| 42 47 |  | 
| 43 48 | 
             
                    RECEIVER_SELECTOR_REPLACEMENTS = IceNine.deep_freeze(
         | 
| @@ -79,6 +84,7 @@ module Mutant | |
| 79 84 | 
             
                    end
         | 
| 80 85 |  | 
| 81 86 | 
             
                    def emit_selector_specific_mutations
         | 
| 87 | 
            +
                      emit_predicate_mutations
         | 
| 82 88 | 
             
                      emit_array_mutation
         | 
| 83 89 | 
             
                      emit_static_send
         | 
| 84 90 | 
             
                      emit_const_get_mutation
         | 
| @@ -88,6 +94,13 @@ module Mutant | |
| 88 94 | 
             
                      emit_lambda_mutation
         | 
| 89 95 | 
             
                    end
         | 
| 90 96 |  | 
| 97 | 
            +
                    def emit_predicate_mutations
         | 
| 98 | 
            +
                      return unless selector.match?(/\?\z/) && !selector.equal?(:defined?)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                      emit(s(:true))
         | 
| 101 | 
            +
                      emit(s(:false))
         | 
| 102 | 
            +
                    end
         | 
| 103 | 
            +
             | 
| 91 104 | 
             
                    def emit_array_mutation
         | 
| 92 105 | 
             
                      return unless selector.equal?(:Array) && possible_kernel_method?
         | 
| 93 106 |  | 
| @@ -175,7 +188,11 @@ module Mutant | |
| 175 188 | 
             
                    end
         | 
| 176 189 |  | 
| 177 190 | 
             
                    def emit_argument_propagation
         | 
| 178 | 
            -
                       | 
| 191 | 
            +
                      return unless arguments.one?
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                      argument = Mutant::Util.one(arguments)
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                      emit_propagation(argument) unless n_kwargs?(argument)
         | 
| 179 196 | 
             
                    end
         | 
| 180 197 |  | 
| 181 198 | 
             
                    def mutate_receiver
         | 
    
        data/lib/mutant/parallel.rb
    CHANGED
    
    | @@ -6,45 +6,61 @@ module Mutant | |
| 6 6 |  | 
| 7 7 | 
             
                # Run async computation returning driver
         | 
| 8 8 | 
             
                #
         | 
| 9 | 
            +
                # @param [World] world
         | 
| 9 10 | 
             
                # @param [Config] config
         | 
| 10 11 | 
             
                #
         | 
| 11 12 | 
             
                # @return [Driver]
         | 
| 12 | 
            -
                def self.async(config)
         | 
| 13 | 
            -
                  shared | 
| 14 | 
            -
             | 
| 15 | 
            -
                    var_final:       shared(Variable::IVar, config),
         | 
| 16 | 
            -
                    var_sink:        shared(Variable::IVar, config, value: config.sink)
         | 
| 17 | 
            -
                  }
         | 
| 13 | 
            +
                def self.async(world, config)
         | 
| 14 | 
            +
                  shared  = shared_state(world, config)
         | 
| 15 | 
            +
                  workers = workers(world, config, shared)
         | 
| 18 16 |  | 
| 19 17 | 
             
                  Driver.new(
         | 
| 20 | 
            -
                     | 
| 18 | 
            +
                    workers: workers,
         | 
| 19 | 
            +
                    threads: threads(world, config, workers),
         | 
| 21 20 | 
             
                    **shared
         | 
| 22 21 | 
             
                  )
         | 
| 23 22 | 
             
                end
         | 
| 24 23 |  | 
| 25 | 
            -
                 | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
                     | 
| 34 | 
            -
             | 
| 35 | 
            -
                    **shared
         | 
| 36 | 
            -
                  )
         | 
| 24 | 
            +
                def self.workers(world, config, shared)
         | 
| 25 | 
            +
                  Array.new(config.jobs) do |index|
         | 
| 26 | 
            +
                    Worker.start(
         | 
| 27 | 
            +
                      block:        config.block,
         | 
| 28 | 
            +
                      index:        index,
         | 
| 29 | 
            +
                      process_name: "#{config.process_name}-#{index}",
         | 
| 30 | 
            +
                      world:        world,
         | 
| 31 | 
            +
                      **shared
         | 
| 32 | 
            +
                    )
         | 
| 33 | 
            +
                  end
         | 
| 37 34 | 
             
                end
         | 
| 35 | 
            +
                private_class_method :workers
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def self.shared_state(world, config)
         | 
| 38 | 
            +
                  {
         | 
| 39 | 
            +
                    var_active_jobs: shared(Variable::IVar, world, value: Set.new),
         | 
| 40 | 
            +
                    var_final:       shared(Variable::IVar, world),
         | 
| 41 | 
            +
                    var_running:     shared(Variable::MVar, world, value: config.jobs),
         | 
| 42 | 
            +
                    var_sink:        shared(Variable::IVar, world, value: config.sink),
         | 
| 43 | 
            +
                    var_source:      shared(Variable::IVar, world, value: config.source)
         | 
| 44 | 
            +
                  }
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                private_class_method :shared_state
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def self.threads(world, config, workers)
         | 
| 49 | 
            +
                  thread = world.thread
         | 
| 38 50 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 51 | 
            +
                  workers.map do |worker|
         | 
| 52 | 
            +
                    thread.new do
         | 
| 53 | 
            +
                      thread.current.name = "#{config.thread_name}-#{worker.index}"
         | 
| 54 | 
            +
                      worker.call
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  end
         | 
| 41 57 | 
             
                end
         | 
| 42 58 | 
             
                private_class_method :threads
         | 
| 43 59 |  | 
| 44 | 
            -
                def self.shared(klass,  | 
| 60 | 
            +
                def self.shared(klass, world, **attributes)
         | 
| 45 61 | 
             
                  klass.new(
         | 
| 46 | 
            -
                    condition_variable:  | 
| 47 | 
            -
                    mutex:               | 
| 62 | 
            +
                    condition_variable: world.condition_variable,
         | 
| 63 | 
            +
                    mutex:              world.mutex,
         | 
| 48 64 | 
             
                    **attributes
         | 
| 49 65 | 
             
                  )
         | 
| 50 66 | 
             
                end
         | 
| @@ -75,13 +91,12 @@ module Mutant | |
| 75 91 | 
             
                # Parallel run configuration
         | 
| 76 92 | 
             
                class Config
         | 
| 77 93 | 
             
                  include Adamantium::Flat, Anima.new(
         | 
| 78 | 
            -
                    : | 
| 94 | 
            +
                    :block,
         | 
| 79 95 | 
             
                    :jobs,
         | 
| 80 | 
            -
                    : | 
| 81 | 
            -
                    :processor,
         | 
| 96 | 
            +
                    :process_name,
         | 
| 82 97 | 
             
                    :sink,
         | 
| 83 98 | 
             
                    :source,
         | 
| 84 | 
            -
                    : | 
| 99 | 
            +
                    :thread_name
         | 
| 85 100 | 
             
                  )
         | 
| 86 101 | 
             
                end # Config
         | 
| 87 102 |  |