evilution 0.22.6 → 0.22.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f88a719ecd12ca2576f1254f3ef1771359f64345eea28e3537e0d9dae38e2c78
4
- data.tar.gz: 01c65258b5a9d496a566437b74460ff77175d0dbea9988643d048df3b2e18171
3
+ metadata.gz: 953b824799c03617e8e41a67f759c5edbd122b63046f8916e19d215021de5871
4
+ data.tar.gz: 38e3498c7cc763e44a5cded169c035b1a48d02c14c95b9ff4ae0800dd63389cd
5
5
  SHA512:
6
- metadata.gz: 136e6f94f55a9e312b777573bd73391d6ec7d05ac8c7455817341589edf018002836db6e550255ff16deb974e6a320a8e818e08661b7918bd2ac6e2f4e85aea1
7
- data.tar.gz: 8e48faca42c452ba1d8ba1b8800deaf1eafc89d264997f34dc04840324296d2431fdc7e9ccb31f2cff5127862adeb818c15a10da5d060301bdcae0b0352d0cf4
6
+ metadata.gz: cceb0046285ad1efdd63914af840da66354006d97f1f9da0642dcf649e3628a342c6ed5f3c6776f3b76dee7eb41af833033a4c9c18992eaa6773bf1c5da8ca75
7
+ data.tar.gz: 6928979ecd999f213b87c3460179f4a09008894866e31d5e822f214ab521235e8463a389768e40bff065512fc1e55355d0ca249e739cb571210ccd429d94db82
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.22.7] - 2026-04-13
4
+
5
+ ### Fixed
6
+
7
+ - **Rails 8 models with `enum`: every mutation errors with `ArgumentError`** — re-running the class body via `load`/`require` retriggered Rails 8's `detect_enum_conflict!` because the enum's predicate methods already existed from the first load, so mutations scored 0% on any affected file; now `remove_defined_constants` drops constants defined by the mutated source (via `remove_const` on the parent namespace) before re-loading, so the class body runs on a fresh constant and DSLs with conflict detection (enum, and any future DSL with redefinition guards) see a clean slate (#683)
8
+
3
9
  ## [0.22.6] - 2026-04-12
4
10
 
5
11
  ### Fixed
@@ -90,7 +90,9 @@ class Evilution::Integration::Base
90
90
  displace_loaded_feature(mutation.file_path)
91
91
  pin_autoloaded_constants(mutation.original_source)
92
92
  clear_concern_state(mutation.file_path)
93
- require(subpath.delete_suffix(".rb"))
93
+ with_redefinition_recovery(mutation.original_source) do
94
+ require(subpath.delete_suffix(".rb"))
95
+ end
94
96
  end
95
97
 
96
98
  def apply_via_load(mutation)
@@ -100,7 +102,22 @@ class Evilution::Integration::Base
100
102
  File.write(dest, mutation.mutated_source)
101
103
  pin_autoloaded_constants(mutation.original_source)
102
104
  clear_concern_state(mutation.file_path)
103
- load(dest)
105
+ with_redefinition_recovery(mutation.original_source) do
106
+ load(dest)
107
+ end
108
+ end
109
+
110
+ def with_redefinition_recovery(original_source)
111
+ yield
112
+ rescue ArgumentError => e
113
+ raise unless redefinition_conflict?(e)
114
+
115
+ remove_defined_constants(original_source)
116
+ yield
117
+ end
118
+
119
+ def redefinition_conflict?(error)
120
+ error.message.include?("already defined")
104
121
  end
105
122
 
106
123
  def restore_original(_mutation)
@@ -139,6 +156,32 @@ class Evilution::Integration::Base
139
156
  names
140
157
  end
141
158
 
159
+ def remove_defined_constants(source)
160
+ collect_constant_names(Prism.parse(source).value).reverse_each do |name|
161
+ parent_name, _, local_name = name.rpartition("::")
162
+ parent = resolve_loaded_constant_parent(parent_name)
163
+ next unless parent
164
+ next unless parent.const_defined?(local_name, false)
165
+ next if parent.autoload?(local_name)
166
+
167
+ parent.send(:remove_const, local_name.to_sym)
168
+ end
169
+ end
170
+
171
+ def resolve_loaded_constant_parent(parent_name)
172
+ return Object if parent_name.empty?
173
+
174
+ parent_name.split("::").reduce(Object) do |mod, part|
175
+ return nil unless mod.const_defined?(part, false)
176
+ return nil if mod.autoload?(part)
177
+
178
+ resolved = mod.const_get(part, false)
179
+ return nil unless resolved.is_a?(Module)
180
+
181
+ resolved
182
+ end
183
+ end
184
+
142
185
  def clear_concern_state(file_path)
143
186
  return unless defined?(ActiveSupport::Concern)
144
187
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evilution
4
- VERSION = "0.22.6"
4
+ VERSION = "0.22.7"
5
5
  end
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.22.6
4
+ version: 0.22.7
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-04-12 00:00:00.000000000 Z
11
+ date: 2026-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs