evilution 0.16.1 → 0.18.0

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/.migration-hint-ts +1 -1
  3. data/.beads/issues.jsonl +47 -46
  4. data/CHANGELOG.md +48 -0
  5. data/README.md +143 -50
  6. data/docs/ast_pattern_syntax.md +210 -0
  7. data/lib/evilution/ast/pattern/filter.rb +25 -0
  8. data/lib/evilution/ast/pattern/matcher.rb +107 -0
  9. data/lib/evilution/ast/pattern/parser.rb +185 -0
  10. data/lib/evilution/ast/pattern.rb +4 -0
  11. data/lib/evilution/ast/sorbet_sig_detector.rb +52 -0
  12. data/lib/evilution/cli.rb +400 -24
  13. data/lib/evilution/config.rb +43 -2
  14. data/lib/evilution/disable_comment.rb +90 -0
  15. data/lib/evilution/hooks/loader.rb +35 -0
  16. data/lib/evilution/hooks/registry.rb +60 -0
  17. data/lib/evilution/hooks.rb +58 -0
  18. data/lib/evilution/integration/base.rb +4 -0
  19. data/lib/evilution/integration/rspec.rb +6 -2
  20. data/lib/evilution/isolation/fork.rb +5 -0
  21. data/lib/evilution/mcp/session_diff_tool.rb +5 -35
  22. data/lib/evilution/mutator/base.rb +4 -1
  23. data/lib/evilution/mutator/operator/collection_return.rb +33 -0
  24. data/lib/evilution/mutator/operator/defined_check.rb +16 -0
  25. data/lib/evilution/mutator/operator/index_assignment_removal.rb +18 -0
  26. data/lib/evilution/mutator/operator/index_to_dig.rb +58 -0
  27. data/lib/evilution/mutator/operator/index_to_fetch.rb +30 -0
  28. data/lib/evilution/mutator/operator/keyword_argument.rb +91 -0
  29. data/lib/evilution/mutator/operator/mixin_removal.rb +2 -1
  30. data/lib/evilution/mutator/operator/multiple_assignment.rb +47 -0
  31. data/lib/evilution/mutator/operator/pattern_matching_alternative.rb +46 -0
  32. data/lib/evilution/mutator/operator/pattern_matching_array.rb +97 -0
  33. data/lib/evilution/mutator/operator/pattern_matching_guard.rb +44 -0
  34. data/lib/evilution/mutator/operator/regex_capture.rb +43 -0
  35. data/lib/evilution/mutator/operator/scalar_return.rb +37 -0
  36. data/lib/evilution/mutator/operator/splat_operator.rb +46 -0
  37. data/lib/evilution/mutator/operator/superclass_removal.rb +2 -1
  38. data/lib/evilution/mutator/operator/yield_statement.rb +51 -0
  39. data/lib/evilution/mutator/registry.rb +17 -3
  40. data/lib/evilution/parallel/pool.rb +7 -51
  41. data/lib/evilution/parallel/work_queue.rb +224 -0
  42. data/lib/evilution/reporter/cli.rb +22 -1
  43. data/lib/evilution/reporter/html.rb +76 -3
  44. data/lib/evilution/reporter/json.rb +23 -2
  45. data/lib/evilution/reporter/suggestion.rb +115 -1
  46. data/lib/evilution/result/summary.rb +20 -2
  47. data/lib/evilution/runner.rb +133 -13
  48. data/lib/evilution/session/diff.rb +85 -0
  49. data/lib/evilution/session/store.rb +5 -2
  50. data/lib/evilution/version.rb +1 -1
  51. data/lib/evilution.rb +23 -0
  52. metadata +28 -2
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../session"
4
+
5
+ class Evilution::Session::Diff
6
+ Result = Struct.new(:summary, :fixed, :new_survivors, :persistent) do
7
+ def to_h
8
+ {
9
+ "summary" => summary.to_h,
10
+ "fixed" => fixed,
11
+ "new_survivors" => new_survivors,
12
+ "persistent" => persistent
13
+ }
14
+ end
15
+ end
16
+
17
+ SummaryDiff = Struct.new(
18
+ :base_score, :head_score, :score_delta,
19
+ :base_survived, :head_survived,
20
+ :base_total, :head_total,
21
+ :base_killed, :head_killed
22
+ ) do
23
+ def to_h
24
+ {
25
+ "base_score" => base_score,
26
+ "head_score" => head_score,
27
+ "score_delta" => score_delta,
28
+ "base_survived" => base_survived,
29
+ "head_survived" => head_survived,
30
+ "base_total" => base_total,
31
+ "head_total" => head_total,
32
+ "base_killed" => base_killed,
33
+ "head_killed" => head_killed
34
+ }
35
+ end
36
+ end
37
+
38
+ def call(base_data, head_data)
39
+ base_survivors = base_data["survived"] || []
40
+ head_survivors = head_data["survived"] || []
41
+
42
+ base_keys = base_survivors.to_set { |m| mutation_key(m) }
43
+ head_keys = head_survivors.to_set { |m| mutation_key(m) }
44
+
45
+ Result.new(
46
+ summary: build_summary_diff(base_data, head_data),
47
+ fixed: base_survivors.reject { |m| head_keys.include?(mutation_key(m)) },
48
+ new_survivors: head_survivors.reject { |m| base_keys.include?(mutation_key(m)) },
49
+ persistent: head_survivors.select { |m| base_keys.include?(mutation_key(m)) }
50
+ )
51
+ end
52
+
53
+ private
54
+
55
+ def build_summary_diff(base_data, head_data)
56
+ base = extract_summary_values(base_data)
57
+ head = extract_summary_values(head_data)
58
+
59
+ SummaryDiff.new(
60
+ base_score: base[:score],
61
+ head_score: head[:score],
62
+ score_delta: (head[:score] - base[:score]).round(4),
63
+ base_survived: base[:survived],
64
+ head_survived: head[:survived],
65
+ base_total: base[:total],
66
+ head_total: head[:total],
67
+ base_killed: base[:killed],
68
+ head_killed: head[:killed]
69
+ )
70
+ end
71
+
72
+ def extract_summary_values(data)
73
+ summary = data["summary"] || {}
74
+ {
75
+ score: summary["score"] || 0.0,
76
+ survived: summary["survived"] || 0,
77
+ total: summary["total"] || 0,
78
+ killed: summary["killed"] || 0
79
+ }
80
+ end
81
+
82
+ def mutation_key(mutation)
83
+ [mutation["operator"], mutation["file"], mutation["line"], mutation["subject"]]
84
+ end
85
+ end
@@ -69,12 +69,13 @@ class Evilution::Session::Store
69
69
  timed_out_count: summary.timed_out,
70
70
  error_count: summary.errors,
71
71
  neutral_count: summary.neutral,
72
- equivalent_count: summary.equivalent
72
+ equivalent_count: summary.equivalent,
73
+ skipped_count: summary.skipped
73
74
  }
74
75
  end
75
76
 
76
77
  def build_summary(summary)
77
- {
78
+ data = {
78
79
  total: summary.total,
79
80
  killed: summary.killed,
80
81
  survived: summary.survived,
@@ -85,6 +86,8 @@ class Evilution::Session::Store
85
86
  score: summary.score.round(4),
86
87
  duration: summary.duration.round(4)
87
88
  }
89
+ data[:skipped] = summary.skipped if summary.skipped.positive?
90
+ data
88
91
  end
89
92
 
90
93
  def build_mutation_detail(result)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evilution
4
- VERSION = "0.16.1"
4
+ VERSION = "0.18.0"
5
5
  end
data/lib/evilution.rb CHANGED
@@ -11,6 +11,13 @@ require_relative "evilution/parallel"
11
11
  require_relative "evilution/ast/source_surgeon"
12
12
  require_relative "evilution/ast/parser"
13
13
  require_relative "evilution/ast/inheritance_scanner"
14
+ require_relative "evilution/ast/pattern"
15
+ require_relative "evilution/ast/sorbet_sig_detector"
16
+ require_relative "evilution/ast/pattern/matcher"
17
+ require_relative "evilution/ast/pattern/parser"
18
+ require_relative "evilution/hooks"
19
+ require_relative "evilution/hooks/registry"
20
+ require_relative "evilution/hooks/loader"
14
21
  require_relative "evilution/mutator"
15
22
  require_relative "evilution/mutator/base"
16
23
  require_relative "evilution/mutator/operator"
@@ -42,6 +49,8 @@ require_relative "evilution/mutator/operator/receiver_replacement"
42
49
  require_relative "evilution/mutator/operator/send_mutation"
43
50
  require_relative "evilution/mutator/operator/argument_nil_substitution"
44
51
  require_relative "evilution/mutator/operator/compound_assignment"
52
+ require_relative "evilution/mutator/operator/keyword_argument"
53
+ require_relative "evilution/mutator/operator/multiple_assignment"
45
54
  require_relative "evilution/mutator/operator/mixin_removal"
46
55
  require_relative "evilution/mutator/operator/superclass_removal"
47
56
  require_relative "evilution/mutator/operator/local_variable_assignment"
@@ -60,6 +69,18 @@ require_relative "evilution/mutator/operator/bitwise_replacement"
60
69
  require_relative "evilution/mutator/operator/bitwise_complement"
61
70
  require_relative "evilution/mutator/operator/zsuper_removal"
62
71
  require_relative "evilution/mutator/operator/explicit_super_mutation"
72
+ require_relative "evilution/mutator/operator/index_to_fetch"
73
+ require_relative "evilution/mutator/operator/index_to_dig"
74
+ require_relative "evilution/mutator/operator/index_assignment_removal"
75
+ require_relative "evilution/mutator/operator/pattern_matching_guard"
76
+ require_relative "evilution/mutator/operator/pattern_matching_alternative"
77
+ require_relative "evilution/mutator/operator/pattern_matching_array"
78
+ require_relative "evilution/mutator/operator/collection_return"
79
+ require_relative "evilution/mutator/operator/scalar_return"
80
+ require_relative "evilution/mutator/operator/yield_statement"
81
+ require_relative "evilution/mutator/operator/splat_operator"
82
+ require_relative "evilution/mutator/operator/defined_check"
83
+ require_relative "evilution/mutator/operator/regex_capture"
63
84
  require_relative "evilution/mutator/registry"
64
85
  require_relative "evilution/equivalent"
65
86
  require_relative "evilution/equivalent/heuristic"
@@ -70,6 +91,7 @@ require_relative "evilution/isolation/in_process"
70
91
  require_relative "evilution/parallel/pool"
71
92
  require_relative "evilution/session"
72
93
  require_relative "evilution/session/store"
94
+ require_relative "evilution/session/diff"
73
95
  require_relative "evilution/git"
74
96
  require_relative "evilution/git/changed_files"
75
97
  require_relative "evilution/integration"
@@ -87,6 +109,7 @@ require_relative "evilution/spec_resolver"
87
109
  require_relative "evilution/baseline"
88
110
  require_relative "evilution/cache"
89
111
  require_relative "evilution/cli"
112
+ require_relative "evilution/disable_comment"
90
113
  require_relative "evilution/runner"
91
114
 
92
115
  module Evilution
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evilution
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Kiselev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-29 00:00:00.000000000 Z
11
+ date: 2026-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -76,16 +76,23 @@ files:
76
76
  - README.md
77
77
  - Rakefile
78
78
  - claude-swarm.yml
79
+ - docs/ast_pattern_syntax.md
79
80
  - exe/evilution
80
81
  - lib/evilution.rb
81
82
  - lib/evilution/ast.rb
82
83
  - lib/evilution/ast/inheritance_scanner.rb
83
84
  - lib/evilution/ast/parser.rb
85
+ - lib/evilution/ast/pattern.rb
86
+ - lib/evilution/ast/pattern/filter.rb
87
+ - lib/evilution/ast/pattern/matcher.rb
88
+ - lib/evilution/ast/pattern/parser.rb
89
+ - lib/evilution/ast/sorbet_sig_detector.rb
84
90
  - lib/evilution/ast/source_surgeon.rb
85
91
  - lib/evilution/baseline.rb
86
92
  - lib/evilution/cache.rb
87
93
  - lib/evilution/cli.rb
88
94
  - lib/evilution/config.rb
95
+ - lib/evilution/disable_comment.rb
89
96
  - lib/evilution/equivalent.rb
90
97
  - lib/evilution/equivalent/detector.rb
91
98
  - lib/evilution/equivalent/heuristic.rb
@@ -97,6 +104,9 @@ files:
97
104
  - lib/evilution/equivalent/heuristic/noop_source.rb
98
105
  - lib/evilution/git.rb
99
106
  - lib/evilution/git/changed_files.rb
107
+ - lib/evilution/hooks.rb
108
+ - lib/evilution/hooks/loader.rb
109
+ - lib/evilution/hooks/registry.rb
100
110
  - lib/evilution/integration.rb
101
111
  - lib/evilution/integration/base.rb
102
112
  - lib/evilution/integration/rspec.rb
@@ -128,42 +138,57 @@ files:
128
138
  - lib/evilution/mutator/operator/break_statement.rb
129
139
  - lib/evilution/mutator/operator/class_variable_write.rb
130
140
  - lib/evilution/mutator/operator/collection_replacement.rb
141
+ - lib/evilution/mutator/operator/collection_return.rb
131
142
  - lib/evilution/mutator/operator/comparison_replacement.rb
132
143
  - lib/evilution/mutator/operator/compound_assignment.rb
133
144
  - lib/evilution/mutator/operator/conditional_branch.rb
134
145
  - lib/evilution/mutator/operator/conditional_flip.rb
135
146
  - lib/evilution/mutator/operator/conditional_negation.rb
147
+ - lib/evilution/mutator/operator/defined_check.rb
136
148
  - lib/evilution/mutator/operator/ensure_removal.rb
137
149
  - lib/evilution/mutator/operator/explicit_super_mutation.rb
138
150
  - lib/evilution/mutator/operator/float_literal.rb
139
151
  - lib/evilution/mutator/operator/global_variable_write.rb
140
152
  - lib/evilution/mutator/operator/hash_literal.rb
153
+ - lib/evilution/mutator/operator/index_assignment_removal.rb
154
+ - lib/evilution/mutator/operator/index_to_dig.rb
155
+ - lib/evilution/mutator/operator/index_to_fetch.rb
141
156
  - lib/evilution/mutator/operator/inline_rescue.rb
142
157
  - lib/evilution/mutator/operator/instance_variable_write.rb
143
158
  - lib/evilution/mutator/operator/integer_literal.rb
159
+ - lib/evilution/mutator/operator/keyword_argument.rb
144
160
  - lib/evilution/mutator/operator/local_variable_assignment.rb
145
161
  - lib/evilution/mutator/operator/method_body_replacement.rb
146
162
  - lib/evilution/mutator/operator/method_call_removal.rb
147
163
  - lib/evilution/mutator/operator/mixin_removal.rb
164
+ - lib/evilution/mutator/operator/multiple_assignment.rb
148
165
  - lib/evilution/mutator/operator/negation_insertion.rb
149
166
  - lib/evilution/mutator/operator/next_statement.rb
150
167
  - lib/evilution/mutator/operator/nil_replacement.rb
168
+ - lib/evilution/mutator/operator/pattern_matching_alternative.rb
169
+ - lib/evilution/mutator/operator/pattern_matching_array.rb
170
+ - lib/evilution/mutator/operator/pattern_matching_guard.rb
151
171
  - lib/evilution/mutator/operator/range_replacement.rb
152
172
  - lib/evilution/mutator/operator/receiver_replacement.rb
153
173
  - lib/evilution/mutator/operator/redo_statement.rb
174
+ - lib/evilution/mutator/operator/regex_capture.rb
154
175
  - lib/evilution/mutator/operator/regexp_mutation.rb
155
176
  - lib/evilution/mutator/operator/rescue_body_replacement.rb
156
177
  - lib/evilution/mutator/operator/rescue_removal.rb
157
178
  - lib/evilution/mutator/operator/return_value_removal.rb
179
+ - lib/evilution/mutator/operator/scalar_return.rb
158
180
  - lib/evilution/mutator/operator/send_mutation.rb
181
+ - lib/evilution/mutator/operator/splat_operator.rb
159
182
  - lib/evilution/mutator/operator/statement_deletion.rb
160
183
  - lib/evilution/mutator/operator/string_literal.rb
161
184
  - lib/evilution/mutator/operator/superclass_removal.rb
162
185
  - lib/evilution/mutator/operator/symbol_literal.rb
186
+ - lib/evilution/mutator/operator/yield_statement.rb
163
187
  - lib/evilution/mutator/operator/zsuper_removal.rb
164
188
  - lib/evilution/mutator/registry.rb
165
189
  - lib/evilution/parallel.rb
166
190
  - lib/evilution/parallel/pool.rb
191
+ - lib/evilution/parallel/work_queue.rb
167
192
  - lib/evilution/reporter.rb
168
193
  - lib/evilution/reporter/cli.rb
169
194
  - lib/evilution/reporter/html.rb
@@ -175,6 +200,7 @@ files:
175
200
  - lib/evilution/result/summary.rb
176
201
  - lib/evilution/runner.rb
177
202
  - lib/evilution/session.rb
203
+ - lib/evilution/session/diff.rb
178
204
  - lib/evilution/session/store.rb
179
205
  - lib/evilution/spec_resolver.rb
180
206
  - lib/evilution/subject.rb