mutant 0.11.12 → 0.11.15

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mutant +40 -35
  3. data/lib/mutant/ast/find_metaclass_containing.rb +6 -6
  4. data/lib/mutant/ast/meta/const.rb +1 -1
  5. data/lib/mutant/ast/meta/optarg.rb +1 -1
  6. data/lib/mutant/ast/meta/resbody.rb +1 -1
  7. data/lib/mutant/ast/meta/send.rb +1 -1
  8. data/lib/mutant/ast/meta/symbol.rb +1 -1
  9. data/lib/mutant/ast/meta.rb +1 -1
  10. data/lib/mutant/ast/named_children.rb +1 -1
  11. data/lib/mutant/ast/node_predicates.rb +1 -1
  12. data/lib/mutant/ast/nodes.rb +1 -1
  13. data/lib/mutant/ast/pattern/lexer.rb +1 -1
  14. data/lib/mutant/ast/pattern/parser.rb +1 -1
  15. data/lib/mutant/ast/pattern/source.rb +1 -1
  16. data/lib/mutant/ast/pattern/token.rb +1 -1
  17. data/lib/mutant/ast/pattern.rb +1 -1
  18. data/lib/mutant/ast/regexp/transformer/direct.rb +1 -1
  19. data/lib/mutant/ast/regexp/transformer/named_group.rb +1 -1
  20. data/lib/mutant/ast/regexp/transformer/options_group.rb +1 -1
  21. data/lib/mutant/ast/regexp/transformer/quantifier.rb +1 -1
  22. data/lib/mutant/ast/regexp/transformer/recursive.rb +1 -1
  23. data/lib/mutant/ast/regexp/transformer/root.rb +1 -1
  24. data/lib/mutant/ast/regexp/transformer/text.rb +1 -1
  25. data/lib/mutant/ast/regexp/transformer.rb +1 -1
  26. data/lib/mutant/ast/regexp.rb +1 -1
  27. data/lib/mutant/ast/sexp.rb +1 -1
  28. data/lib/mutant/ast/structure.rb +8 -3
  29. data/lib/mutant/ast/types.rb +1 -1
  30. data/lib/mutant/ast.rb +31 -29
  31. data/lib/mutant/cli/command/environment/run.rb +0 -7
  32. data/lib/mutant/cli/command/environment.rb +4 -5
  33. data/lib/mutant/cli/command.rb +24 -22
  34. data/lib/mutant/cli.rb +2 -4
  35. data/lib/mutant/config.rb +4 -16
  36. data/lib/mutant/license/subscription/opensource.rb +12 -2
  37. data/lib/mutant/matcher/method/instance.rb +3 -2
  38. data/lib/mutant/matcher/method/metaclass.rb +4 -3
  39. data/lib/mutant/matcher/method/singleton.rb +3 -2
  40. data/lib/mutant/matcher/method.rb +32 -23
  41. data/lib/mutant/mutator/node/block.rb +5 -3
  42. data/lib/mutant/parser.rb +0 -7
  43. data/lib/mutant/version.rb +1 -1
  44. data/lib/mutant.rb +2 -3
  45. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c75928a9c55d93ebfad196c028271b8c82d7d9eb94e48873ac75c9ee4bb212f
4
- data.tar.gz: 27149ec498db15629bb18c55a5840e3ea8c369542a85bf9d3658cadc78fc8f4a
3
+ metadata.gz: 4f0fc5ddcee197485af9a005a41938eb5c056fe7112747e1ed5cefd7860e0d27
4
+ data.tar.gz: eed2005705a2ff4a58c18390d7f59cf4eff85aa67b6c3846cb44b014e9f3fba9
5
5
  SHA512:
6
- metadata.gz: 44867690e5c1c367df8b22ec3fa5b35941328e12fd10a26a252baa3815c955fbd37f1adaaaadfafbcdc1f72280ce013d37996d001c163930c084b95b07905362
7
- data.tar.gz: b22e71a0ae7f1ecb96345e7996e61c4ee843c7b82442f21dea3516be132503fa9c0193443f1d7da9196fbb27f23f3ef858ee58f81c03b7cda8d4f4dcced1a9a7
6
+ metadata.gz: ff9b7d961960b339405eda6b0bf16bbcc7ad0527d52787f7fe402c0689afea3f0e344697af9a87e5331c766b8002ccc03c34b517f47b3edea385948336889634
7
+ data.tar.gz: bfe080deae82a8b5aae5a281515344ecfd526e8fafc1350727608b989404cf34c821fedd42e1e8c04b8bca744a28d0ad66f2d273871cc044197556eec8ebad48
data/bin/mutant CHANGED
@@ -8,43 +8,48 @@ end
8
8
 
9
9
  require 'mutant'
10
10
 
11
- command = Mutant::CLI.parse(
11
+ Mutant::CLI.parse(
12
12
  arguments: ARGV,
13
13
  world: Mutant::WORLD
14
- )
14
+ ).either(
15
+ ->(message) { Mutant::WORLD.stderr.puts(message); Kernel.exit(false) },
16
+ # rubocop:disable Metrics/BlockLength
17
+ lambda do |command|
18
+ status =
19
+ if command.zombie?
20
+ $stderr.puts('Running mutant zombified!')
21
+ Mutant::Zombifier.call(
22
+ namespace: :Zombie,
23
+ load_path: $LOAD_PATH,
24
+ kernel: Kernel,
25
+ pathname: Pathname,
26
+ require_highjack: Mutant::RequireHighjack
27
+ .public_method(:call)
28
+ .to_proc
29
+ .curry
30
+ .call(Kernel),
31
+ root_require: 'mutant',
32
+ includes: %w[
33
+ adamantium
34
+ anima
35
+ concord
36
+ equalizer
37
+ mprelude
38
+ mutant
39
+ unparser
40
+ variable
41
+ ]
42
+ )
15
43
 
16
- status =
17
- if command.zombie?
18
- $stderr.puts('Running mutant zombified!')
19
- Mutant::Zombifier.call(
20
- namespace: :Zombie,
21
- load_path: $LOAD_PATH,
22
- kernel: Kernel,
23
- pathname: Pathname,
24
- require_highjack: Mutant::RequireHighjack
25
- .public_method(:call)
26
- .to_proc
27
- .curry
28
- .call(Kernel),
29
- root_require: 'mutant',
30
- includes: %w[
31
- adamantium
32
- anima
33
- concord
34
- equalizer
35
- mprelude
36
- mutant
37
- unparser
38
- variable
39
- ]
40
- )
44
+ Zombie::Mutant::CLI.parse(
45
+ arguments: ARGV,
46
+ world: Zombie::Mutant::WORLD
47
+ ).from_right.call
48
+ else
49
+ command.call
50
+ end
41
51
 
42
- Zombie::Mutant::CLI.parse(
43
- arguments: ARGV,
44
- world: Zombie::Mutant::WORLD
45
- ).call
46
- else
47
- command.call
52
+ Kernel.exit(status)
48
53
  end
49
-
50
- Kernel.exit(status)
54
+ # rubocop:enable Metrics/BlockLength
55
+ )
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Given an AST, finds the sclass that directly(-ish) contains the provided
6
6
  # node.
7
7
  # This won't match arbitrarily complex structures - it only searches the
@@ -10,7 +10,7 @@ module Mutant
10
10
  # Descending into 'begin' nodes is supported because these are generated for
11
11
  # the one-line syntax class << self; def foo; end
12
12
  class FindMetaclassContaining
13
- include NodePredicates, Concord.new(:root, :target), Procto
13
+ include NodePredicates, Concord.new(:ast, :target), Procto
14
14
 
15
15
  SCLASS_BODY_INDEX = 1
16
16
 
@@ -22,11 +22,11 @@ module Mutant
22
22
  #
23
23
  # @api private
24
24
  def call
25
- AST.find_last_path(root) do |current|
26
- next unless n_sclass?(current)
25
+ Structure.for(ast.node.type).each_node(ast.node) do |current|
26
+ return current if n_sclass?(current) && metaclass_of?(current)
27
+ end
27
28
 
28
- metaclass_of?(current)
29
- end.last
29
+ nil
30
30
  end
31
31
 
32
32
  private
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Node meta information mixin
6
6
  module Meta
7
7
  end # Meta
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
 
6
6
  # Helper methods to define named children
7
7
  module NamedChildren
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Module for node predicates
6
6
  module NodePredicates
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Singleton nodes
6
6
  module Nodes
7
7
  extend Sexp
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class Lexer
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # rubocop:disable Metrics/ClassLength
6
6
  # rubocop:disable Metrics/MethodLength
7
7
  class Pattern
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  class Source
7
7
  include Anima.new(:string)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  class Token
7
7
  include Anima.new(:type, :value, :location)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  class Pattern
6
6
  include Adamantium
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for nodes which map directly to other domain
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for named groups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for option groups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for regexp quantifiers
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for nodes with children
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Transformer for root nodes
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  class Transformer
7
7
  # Regexp AST transformer for nodes that encode a text value
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  module Regexp
6
6
  # Regexp bijective mapper
7
7
  #
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Regexp source mapper
6
6
  module Regexp
7
7
  # Parse regex string into expression
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Mixin for node sexp syntax
6
6
  module Sexp
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # AST Structure metadata
6
6
  # rubocop:disable Metrics/ModuleLength
7
7
  module Structure
@@ -26,7 +26,7 @@ module Mutant
26
26
  end
27
27
 
28
28
  def value(node)
29
- node.children.fetch(index)
29
+ node.children.at(index)
30
30
  end
31
31
  end
32
32
 
@@ -246,7 +246,7 @@ module Mutant
246
246
  type: :class,
247
247
  fixed: Node.fixed(
248
248
  [
249
- [Node::Fixed::Descendant, :name],
249
+ [Node::Fixed::Attribute, :name],
250
250
  [Node::Fixed::Descendant, :superclass],
251
251
  [Node::Fixed::Descendant, :body]
252
252
  ]
@@ -386,6 +386,11 @@ module Mutant
386
386
  fixed: Node.fixed([[Node::Fixed::Attribute, :value]]),
387
387
  variable: nil
388
388
  ),
389
+ Node.new(
390
+ type: :forwarded_args,
391
+ fixed: EMPTY_ARRAY,
392
+ variable: nil
393
+ ),
389
394
  Node.new(
390
395
  type: :for,
391
396
  fixed: Node.fixed(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- module AST
4
+ class AST
5
5
  # Groups of node types
6
6
  module Types # rubocop:disable Metrics/ModuleLength
7
7
  ASSIGNABLE_VARIABLES = Set.new(%i[ivasgn lvasgn cvasgn gvasgn]).freeze
data/lib/mutant/ast.rb CHANGED
@@ -1,41 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mutant
4
- # AST helpers
5
- module AST
6
-
7
- # Find last node satisfying predicate (as block)
8
- #
9
- # @return [Parser::AST::Node]
10
- # if satisfying node is found
11
- #
12
- # @yield [Parser::AST::Node]
13
- #
14
- # @yieldreturn [Boolean]
15
- # true in case node satisfies predicate
16
- #
17
- # @return [nil]
18
- # otherwise
19
- def self.find_last_path(node, &predicate)
20
- fail ArgumentError, 'block expected' unless block_given?
21
- path = []
22
- walk(node, [node]) do |candidate, stack|
23
- if predicate.call(candidate)
24
- path = stack.dup
25
- end
4
+ class AST
5
+ include Adamantium, Anima.new(
6
+ :node,
7
+ :comment_associations
8
+ )
9
+
10
+ class View
11
+ include Adamantium, Anima.new(:node, :path)
12
+ end
13
+
14
+ def on_line(line)
15
+ line_map.fetch(line, EMPTY_HASH).map do |node, path|
16
+ View.new(node: node, path: path)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def line_map
23
+ line_map = {}
24
+
25
+ walk_path(node) do |node, path|
26
+ expression = node.location.expression || next
27
+ (line_map[expression.line] ||= []) << [node, path]
26
28
  end
27
- path
29
+
30
+ line_map
28
31
  end
32
+ memoize :line_map
29
33
 
30
- def self.walk(node, stack, &block)
31
- block.call(node, stack)
34
+ def walk_path(node, stack = [node.type], &block)
35
+ block.call(node, stack.dup)
32
36
  node.children.grep(::Parser::AST::Node) do |child|
33
- stack.push(child)
34
- walk(child, stack, &block)
37
+ stack.push(child.type)
38
+ walk_path(child, stack, &block)
35
39
  stack.pop
36
40
  end
37
41
  end
38
- private_class_method :walk
39
-
40
42
  end # AST
41
43
  end # Mutant
@@ -30,13 +30,6 @@ module Mutant
30
30
  ===============
31
31
  MESSAGE
32
32
 
33
- # Test if command needs to be executed in zombie environment
34
- #
35
- # @return [Bool]
36
- def zombie?
37
- @config.zombie
38
- end
39
-
40
33
  private
41
34
 
42
35
  def action
@@ -19,7 +19,9 @@ module Mutant
19
19
 
20
20
  def initialize(attributes)
21
21
  super(attributes)
22
- @config = Config::DEFAULT
22
+ @config = Config::DEFAULT.with(
23
+ coverage_criteria: Config::CoverageCriteria::EMPTY
24
+ )
23
25
  end
24
26
 
25
27
  def bootstrap
@@ -37,7 +39,7 @@ module Mutant
37
39
  )
38
40
  end
39
41
 
40
- @config = Config.env.merge(file_config).merge(@config).expand_defaults
42
+ @config = Config.env.merge(file_config).merge(@config)
41
43
  end
42
44
 
43
45
  def parse_remaining_arguments(arguments)
@@ -67,9 +69,6 @@ module Mutant
67
69
  # rubocop:disable Metrics/MethodLength
68
70
  def add_environment_options(parser)
69
71
  parser.separator('Environment:')
70
- parser.on('--zombie', 'Run mutant zombified') do
71
- set(zombie: true)
72
- end
73
72
  parser.on('-I', '--include DIRECTORY', 'Add DIRECTORY to $LOAD_PATH') do |directory|
74
73
  add(:includes, directory)
75
74
  end
@@ -4,9 +4,7 @@ module Mutant
4
4
  module CLI
5
5
  # rubocop:disable Metrics/ClassLength
6
6
  class Command
7
- include AbstractType, Anima.new(:world, :main, :parent, :arguments)
8
-
9
- include Equalizer.new(:parent, :arguments)
7
+ include AbstractType, Anima.new(:world, :main, :parent, :zombie)
10
8
 
11
9
  OPTIONS = [].freeze
12
10
  SUBCOMMANDS = [].freeze
@@ -18,21 +16,20 @@ module Mutant
18
16
  define_method(:add_officious) {}
19
17
  end # OptionParser
20
18
 
21
- class FailParse < self
22
- include Concord.new(:world, :message)
23
-
24
- def call
25
- world.stderr.puts(message)
26
- false
27
- end
28
- end
29
-
30
19
  # Parse command
31
20
  #
32
21
  # @return [Command]
33
- def self.parse(**attributes)
34
- new(main: nil, parent: nil, **attributes).__send__(:parse)
22
+ #
23
+ # rubocop:disable Metrics/ParameterLists
24
+ def self.parse(arguments:, parent: nil, world:, zombie: false)
25
+ new(
26
+ main: nil,
27
+ parent: parent,
28
+ world: world,
29
+ zombie: zombie
30
+ ).__send__(:parse, arguments)
35
31
  end
32
+ # rubocop:enable Metrics/ParameterLists
36
33
 
37
34
  # Command name
38
35
  #
@@ -62,12 +59,7 @@ module Mutant
62
59
  [*parent&.full_name, self.class.command_name].join(' ')
63
60
  end
64
61
 
65
- # Test if command needs to be executed in zombie environment
66
- #
67
- # @return [Bool]
68
- def zombie?
69
- false
70
- end
62
+ alias_method :zombie?, :zombie
71
63
 
72
64
  abstract_method :action
73
65
 
@@ -116,7 +108,7 @@ module Mutant
116
108
  end
117
109
  end
118
110
 
119
- def parse
111
+ def parse(arguments)
120
112
  Either
121
113
  .wrap_error(OptionParser::InvalidOption) { parser.order(arguments) }
122
114
  .lmap(&method(:with_help))
@@ -129,6 +121,7 @@ module Mutant
129
121
  parser.separator(nil)
130
122
  end
131
123
 
124
+ # rubocop:disable Metrics/MethodLength
132
125
  def add_global_options(parser)
133
126
  parser.separator("mutant version: #{VERSION}")
134
127
  parser.separator(nil)
@@ -142,6 +135,10 @@ module Mutant
142
135
  parser.on('--version', 'Print mutants version') do
143
136
  capture_main { world.stdout.puts("mutant-#{VERSION}"); true }
144
137
  end
138
+
139
+ parser.on('--zombie', 'Run mutant zombified') do
140
+ @zombie = true
141
+ end
145
142
  end
146
143
 
147
144
  def add_subcommands(parser)
@@ -178,7 +175,12 @@ module Mutant
178
175
  Either::Left.new(with_help('Missing required subcommand!'))
179
176
  else
180
177
  find_command(command_name).bind do |command|
181
- command.parse(**to_h, parent: self, arguments: arguments)
178
+ command.parse(
179
+ arguments: arguments,
180
+ parent: self,
181
+ world: world,
182
+ zombie: zombie
183
+ )
182
184
  end
183
185
  end
184
186
  end
data/lib/mutant/cli.rb CHANGED
@@ -6,10 +6,8 @@ module Mutant
6
6
  # Parse command
7
7
  #
8
8
  # @return [Command]
9
- def self.parse(world:, **attributes)
10
- Command::Root
11
- .parse(world: world, **attributes)
12
- .from_right { |message| Command::FailParse.new(world, message) }
9
+ def self.parse(arguments:, world:)
10
+ Command::Root.parse(arguments: arguments, world: world)
13
11
  end
14
12
  end # CLI
15
13
  end # Mutant
data/lib/mutant/config.rb CHANGED
@@ -21,11 +21,10 @@ module Mutant
21
21
  :matcher,
22
22
  :mutation,
23
23
  :reporter,
24
- :requires,
25
- :zombie
24
+ :requires
26
25
  )
27
26
 
28
- %i[fail_fast zombie].each do |name|
27
+ %i[fail_fast].each do |name|
29
28
  define_method(:"#{name}?") { public_send(name) }
30
29
  end
31
30
 
@@ -42,7 +41,7 @@ module Mutant
42
41
  MUTATION_TIMEOUT_DEPRECATION = <<~'MESSAGE'
43
42
  Deprecated configuration toplevel key `mutation_timeout` found.
44
43
 
45
- This key will be removed in the next mayor version.
44
+ This key will be removed in the next major version.
46
45
  Instead place your mutation timeout configuration under the `mutation` key
47
46
  like this:
48
47
 
@@ -74,8 +73,7 @@ module Mutant
74
73
  jobs: other.jobs || jobs,
75
74
  matcher: matcher.merge(other.matcher),
76
75
  mutation: mutation.merge(other.mutation),
77
- requires: requires + other.requires,
78
- zombie: zombie || other.zombie
76
+ requires: requires + other.requires
79
77
  )
80
78
  end
81
79
  # rubocop:enable Metrics/AbcSize
@@ -100,16 +98,6 @@ module Mutant
100
98
  end
101
99
  end
102
100
 
103
- # Expand config with defaults
104
- #
105
- # @return [Config]
106
- def expand_defaults
107
- with(
108
- coverage_criteria: CoverageCriteria::DEFAULT.merge(coverage_criteria),
109
- jobs: jobs || 1
110
- )
111
- end
112
-
113
101
  def self.load_contents(env, path)
114
102
  Transform::Named
115
103
  .new(
@@ -39,7 +39,17 @@ module Mutant
39
39
  new(match[:host], match[:path].downcase)
40
40
  end
41
41
  private_class_method :parse_url
42
- end
42
+
43
+ def allow?(other)
44
+ other.host.eql?(host) && path_match?(other.path)
45
+ end
46
+
47
+ private
48
+
49
+ def path_match?(other_path)
50
+ path.eql?(other_path) || (path.end_with?('/*') && other_path.start_with?(path[..-2]))
51
+ end
52
+ end # Opensource
43
53
 
44
54
  def self.from_json(value)
45
55
  new(
@@ -60,7 +70,7 @@ module Mutant
60
70
  private
61
71
 
62
72
  def check_subscription(actual)
63
- if (licensed & actual).any?
73
+ if licensed.any? { |repository| actual.any? { |other| repository.allow?(other) } }
64
74
  success
65
75
  else
66
76
  failure(licensed, actual)
@@ -30,8 +30,9 @@ module Mutant
30
30
 
31
31
  # Instance method specific evaluator
32
32
  class Evaluator < Evaluator
33
- SUBJECT_CLASS = Subject::Method::Instance
34
- NAME_INDEX = 0
33
+ MATCH_NODE_TYPE = :def
34
+ NAME_INDEX = 0
35
+ SUBJECT_CLASS = Subject::Method::Instance
35
36
 
36
37
  private
37
38
 
@@ -22,10 +22,11 @@ module Mutant
22
22
  # Metaclass method evaluator
23
23
  class Evaluator < Evaluator
24
24
  # Terminology note: the "receiver" is the `self` in `class << self`
25
- SUBJECT_CLASS = Subject::Method::Metaclass
26
- NAME_INDEX = 0
27
25
  CONST_NAME_INDEX = 1
26
+ MATCH_NODE_TYPE = :def
27
+ NAME_INDEX = 0
28
28
  SCLASS_RECEIVER_INDEX = 0
29
+ SUBJECT_CLASS = Subject::Method::Metaclass
29
30
  RECEIVER_WARNING = 'Can only match :def inside :sclass on ' \
30
31
  ':self or :const, got :sclass on %p ' \
31
32
  'unable to match'
@@ -45,7 +46,7 @@ module Mutant
45
46
  end
46
47
 
47
48
  def metaclass_containing(node)
48
- AST::FindMetaclassContaining.call(ast.node, node)
49
+ AST::FindMetaclassContaining.call(ast, node)
49
50
  end
50
51
 
51
52
  def line?(node)
@@ -18,10 +18,11 @@ module Mutant
18
18
 
19
19
  # Singleton method evaluator
20
20
  class Evaluator < Evaluator
21
- SUBJECT_CLASS = Subject::Method::Singleton
22
- RECEIVER_INDEX = 0
21
+ MATCH_NODE_TYPE = :defs
23
22
  NAME_INDEX = 1
23
+ RECEIVER_INDEX = 0
24
24
  RECEIVER_WARNING = 'Can only match :defs on :self or :const got %p unable to match'
25
+ SUBJECT_CLASS = Subject::Method::Singleton
25
26
 
26
27
  private
27
28
 
@@ -41,23 +41,38 @@ module Mutant
41
41
  #
42
42
  # @return [Enumerable<Subject>]
43
43
  def call
44
- return EMPTY_ARRAY if skip?
44
+ location = source_location
45
+
46
+ if location.nil? || !location.first.end_with?('.rb')
47
+ env.warn(SOURCE_LOCATION_WARNING_FORMAT % target_method)
45
48
 
46
- [subject].compact
49
+ return EMPTY_ARRAY
50
+ end
51
+
52
+ match_view
47
53
  end
48
54
 
49
55
  private
50
56
 
51
- def skip?
52
- location = source_location
53
-
54
- file = location&.first
57
+ def match_view
58
+ return EMPTY_ARRAY if matched_view.nil?
55
59
 
56
- if location.nil? || !file.end_with?('.rb')
57
- env.warn(SOURCE_LOCATION_WARNING_FORMAT % target_method)
58
- elsif matched_node_path.any?(&method(:n_block?))
60
+ if matched_view.path.any?(&:block.public_method(:equal?))
59
61
  env.warn(CLOSURE_WARNING_FORMAT % target_method)
62
+
63
+ return EMPTY_ARRAY
60
64
  end
65
+
66
+ [subject]
67
+ end
68
+
69
+ def subject
70
+ self.class::SUBJECT_CLASS.new(
71
+ config: subject_config(matched_view.node),
72
+ context: context,
73
+ node: matched_view.node,
74
+ visibility: visibility
75
+ )
61
76
  end
62
77
 
63
78
  def method_name
@@ -95,17 +110,6 @@ module Mutant
95
110
  T::Private::Methods.signature_for_method(target_method)
96
111
  end
97
112
 
98
- def subject
99
- node = matched_node_path.last || return
100
-
101
- self.class::SUBJECT_CLASS.new(
102
- config: subject_config(node),
103
- context: context,
104
- node: node,
105
- visibility: visibility
106
- )
107
- end
108
-
109
113
  def subject_config(node)
110
114
  Subject::Config.parse(
111
115
  comments: ast.comment_associations.fetch(node, []),
@@ -113,10 +117,15 @@ module Mutant
113
117
  )
114
118
  end
115
119
 
116
- def matched_node_path
117
- AST.find_last_path(ast.node, &method(:match?))
120
+ def matched_view
121
+ return if source_location.nil?
122
+
123
+ ast
124
+ .on_line(source_line)
125
+ .select { |view| view.node.type.eql?(self.class::MATCH_NODE_TYPE) && match?(view.node) }
126
+ .last
118
127
  end
119
- memoize :matched_node_path
128
+ memoize :matched_view
120
129
 
121
130
  def visibility
122
131
  # This can be cleaned up once we are on >ruby-3.0
@@ -38,9 +38,11 @@ module Mutant
38
38
  end
39
39
 
40
40
  def body_has_control?
41
- AST.find_last_path(body) do |node|
42
- n_break?(node) || n_next?(node)
43
- end.any?
41
+ AST::Structure.for(body.type).each_node(body) do |node|
42
+ return true if n_break?(node) || n_next?(node)
43
+ end
44
+
45
+ false
44
46
  end
45
47
 
46
48
  def mutate_body_receiver
data/lib/mutant/parser.rb CHANGED
@@ -5,13 +5,6 @@ module Mutant
5
5
  class Parser
6
6
  include Adamantium, Equalizer.new
7
7
 
8
- class AST
9
- include Anima.new(
10
- :node,
11
- :comment_associations
12
- )
13
- end
14
-
15
8
  # Initialize object
16
9
  #
17
10
  # @return [undefined]
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.12'
5
+ VERSION = '0.11.15'
6
6
  end # Mutant
data/lib/mutant.rb CHANGED
@@ -273,7 +273,7 @@ module Mutant
273
273
  # Reopen class to initialize constant to avoid dep circle
274
274
  class Config
275
275
  DEFAULT = new(
276
- coverage_criteria: Config::CoverageCriteria::EMPTY,
276
+ coverage_criteria: Config::CoverageCriteria::DEFAULT,
277
277
  expression_parser: Expression::Parser.new([
278
278
  Expression::Descendants,
279
279
  Expression::Method,
@@ -291,8 +291,7 @@ module Mutant
291
291
  matcher: Matcher::Config::DEFAULT,
292
292
  mutation: Mutation::Config::DEFAULT,
293
293
  reporter: Reporter::CLI.build(WORLD.stdout),
294
- requires: EMPTY_ARRAY,
295
- zombie: false
294
+ requires: EMPTY_ARRAY
296
295
  )
297
296
  end # Config
298
297
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.12
4
+ version: 0.11.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-27 00:00:00.000000000 Z
11
+ date: 2022-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -393,7 +393,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
393
393
  - !ruby/object:Gem::Version
394
394
  version: '0'
395
395
  requirements: []
396
- rubygems_version: 3.1.6
396
+ rubygems_version: 3.3.7
397
397
  signing_key:
398
398
  specification_version: 4
399
399
  summary: ''