deprecate_soft 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +11 -1
- data/README.md +97 -62
- data/lib/deprecate_soft/method_wrapper.rb +36 -8
- data/lib/deprecate_soft/version.rb +1 -1
- data/lib/deprecate_soft.rb +14 -8
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b9799b61944284b4206b894196574252ccbcf7e550b127d7f45dfe524a943a5
|
4
|
+
data.tar.gz: 1474ec114cd60edcd85a7c975efb69121654f19ea0659ca4b13f577ca9370520
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd8cd841c2c67e77b3b7aed65e4fe0405f19d296c727c051346ba139662c395c3542e2848ee5d9c09146653bd6bdc5fdfa3756fcb57f95412d29a355d729841f
|
7
|
+
data.tar.gz: 8662fc4dec07bfc90b334d3aa5127b5c9042af70168d3013e03045f35d19beec572ffb5f16dfc386e169e48e590c83c600c9c7d823b724a5ee48615a7045f5b7
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
## DepracateSoft Change Log
|
2
2
|
|
3
|
+
## [1.1.0] - 2025-03-29
|
4
|
+
- simplify initialization
|
5
|
+
- added tests for corner cases:
|
6
|
+
- deprecate_soft called before method definition
|
7
|
+
- deprecate_soft called twice
|
8
|
+
- deprecate_soft for private methods
|
9
|
+
- before_hook or after_hook raise
|
10
|
+
- prevent double-wrapping methods
|
11
|
+
- ensure that methods run undisturbed, even if the before_hook or after_hook raise an exception
|
12
|
+
|
3
13
|
## [1.0.0] - 2025-03-24
|
4
14
|
- Initial release
|
15
|
+
|
5
16
|
## [0.0.1] - 2025-03-22
|
6
17
|
- pre-release
|
7
|
-
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
# DeprecateSoft
|
3
3
|
|
4
|
-
DeprecateSoft is a lightweight and flexible Ruby gem designed to help you gracefully and safely
|
4
|
+
DeprecateSoft is a lightweight and flexible Ruby gem designed to help you gracefully and safely delete methods.
|
5
5
|
|
6
6
|
It was inspired by the need to track deprecated method usage in large codebases before safely removing old code — with zero disruption and flexible metrics support.
|
7
7
|
|
@@ -11,6 +11,8 @@ It’s ideal for monitoring deprecated method usage across your application usin
|
|
11
11
|
|
12
12
|
Once tracking confirms that a deprecated method is no longer in use, you can confidently delete it from your codebase.
|
13
13
|
|
14
|
+
This mechanism has been **proven in large-scale production systems** to safely clean up legacy code — this gem reimagines that functionality to help you clean up your code with confidence.
|
15
|
+
|
14
16
|
---
|
15
17
|
|
16
18
|
## ✨ Features
|
@@ -19,9 +21,12 @@ Once tracking confirms that a deprecated method is no longer in use, you can con
|
|
19
21
|
- Works with instance methods in any class or module
|
20
22
|
- Works with class or module methods in any class or module
|
21
23
|
- System-wide hook configuration (before and after)
|
22
|
-
- No monkey-patching or global pollution
|
24
|
+
- No monkey-patching or global pollution — unless you explicitly opt in via `GlobalMonkeyPatch`
|
23
25
|
- Fully compatible with Rails or plain Ruby apps
|
24
26
|
|
27
|
+
---
|
28
|
+
## 📖 Blog Posts
|
29
|
+
- [Safely Delete Old Ruby Code with deprecate_soft](https://medium.com/@tilo-sloboda/safely-delete-old-code-with-deprecate-soft-89e819b41d52)
|
25
30
|
---
|
26
31
|
|
27
32
|
## 🚀 Installation
|
@@ -38,6 +43,62 @@ Then run:
|
|
38
43
|
bundle install
|
39
44
|
```
|
40
45
|
|
46
|
+
And add your initializer file.
|
47
|
+
|
48
|
+
---
|
49
|
+
|
50
|
+
## 🧩 Usage
|
51
|
+
|
52
|
+
Declare `deprecate_soft` **after** the method definition.
|
53
|
+
|
54
|
+
### For Instance Methods:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class MyService
|
58
|
+
include DeprecateSoft
|
59
|
+
|
60
|
+
def deprecated_method(a, b)
|
61
|
+
puts "doing something with #{a} and #{b}"
|
62
|
+
end
|
63
|
+
|
64
|
+
deprecate_soft :deprecated_method, "Use #new_method instead"
|
65
|
+
end
|
66
|
+
|
67
|
+
MyService.new.deprecated_method(1, 2) # will exercise the tracking hooks
|
68
|
+
```
|
69
|
+
|
70
|
+
### For Class Methods:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class MyService
|
74
|
+
extend DeprecateSoft
|
75
|
+
|
76
|
+
def self.deprecated_method(a, b)
|
77
|
+
puts "doing something with #{a} and #{b}"
|
78
|
+
end
|
79
|
+
|
80
|
+
deprecate_soft :deprecated_method, "will be removed"
|
81
|
+
end
|
82
|
+
|
83
|
+
MyService.deprecated_method(1, 2) # will exercise the tracking hooks
|
84
|
+
|
85
|
+
```
|
86
|
+
|
87
|
+
---
|
88
|
+
|
89
|
+
## 🔐 What It Does Under the Hood
|
90
|
+
|
91
|
+
When you call `deprecate_soft :method_name, "reason"`:
|
92
|
+
|
93
|
+
1. It renames the original method to `__method_name_deprecated`.
|
94
|
+
2. It defines a new method with the original name that:
|
95
|
+
- Calls the configured `before_hook` (if set)
|
96
|
+
- Delegates to the original method
|
97
|
+
- Calls the configured `after_hook` (if set)
|
98
|
+
3. The optional `message` with the reason can help identifying alternatives.
|
99
|
+
|
100
|
+
This ensures consistent tracking, clean method resolution, and avoids accidental bypassing.
|
101
|
+
|
41
102
|
---
|
42
103
|
|
43
104
|
## ⚙️ Configuration
|
@@ -96,7 +157,7 @@ end
|
|
96
157
|
|
97
158
|
This setup ensures you can plug in **any tracking backend** you like — without polluting the global namespace.
|
98
159
|
|
99
|
-
### 🔧 Customizing Method Name Wrapping
|
160
|
+
### 🔧 Optional: Customizing Method Name Wrapping
|
100
161
|
|
101
162
|
When `deprecate_soft` wraps a method, it renames the original method internally to preserve its behavior. You can customize how that internal method is named by configuring a `prefix` and `suffix`.
|
102
163
|
|
@@ -137,61 +198,6 @@ This gives you full control over how deprecated methods are renamed internally.
|
|
137
198
|
|
138
199
|
These names are never called directly — they're used internally to wrap and preserve the original method logic.
|
139
200
|
|
140
|
-
|
141
|
-
---
|
142
|
-
|
143
|
-
## 🧩 Usage
|
144
|
-
|
145
|
-
🚨 Always declare `deprecate_soft` **after** the method definition!
|
146
|
-
|
147
|
-
### For Instance Methods:
|
148
|
-
|
149
|
-
```ruby
|
150
|
-
class MyService
|
151
|
-
include DeprecateSoft
|
152
|
-
|
153
|
-
def deprecated_method(a, b)
|
154
|
-
puts "doing something with #{a} and #{b}"
|
155
|
-
end
|
156
|
-
|
157
|
-
deprecate_soft :deprecated_method, "Use #new_method instead"
|
158
|
-
end
|
159
|
-
|
160
|
-
MyService.new.deprecated_method(1, 2) # will exercise the tracking hooks
|
161
|
-
```
|
162
|
-
|
163
|
-
### For Class Methods:
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
class MyService
|
167
|
-
extend DeprecateSoft
|
168
|
-
|
169
|
-
def self.deprecated_method(a, b)
|
170
|
-
puts "doing something with #{a} and #{b}"
|
171
|
-
end
|
172
|
-
|
173
|
-
deprecate_soft :deprecated_method, "will be removed"
|
174
|
-
end
|
175
|
-
|
176
|
-
MyService.deprecated_method(1, 2) # will exercise the tracking hooks
|
177
|
-
|
178
|
-
```
|
179
|
-
|
180
|
-
---
|
181
|
-
|
182
|
-
## 🔐 What It Does Under the Hood
|
183
|
-
|
184
|
-
When you call `deprecate_soft :method_name, "reason"`:
|
185
|
-
|
186
|
-
1. It renames the original method to `__method_name_deprecated`.
|
187
|
-
2. It defines a new method with the original name that:
|
188
|
-
- Calls the configured `before_hook` (if set)
|
189
|
-
- Delegates to the original method
|
190
|
-
- Calls the configured `after_hook` (if set)
|
191
|
-
3. The optional `message` with the reason can help identifying alternatives.
|
192
|
-
|
193
|
-
This ensures consistent tracking, clean method resolution, and avoids accidental bypassing.
|
194
|
-
|
195
201
|
---
|
196
202
|
|
197
203
|
## 🧪 Example Hook Logic
|
@@ -273,6 +279,36 @@ Klass#legacy_method:caller:app/jobs/cleanup_job.rb:88 → 4
|
|
273
279
|
|
274
280
|
💡 Now you not only know that the method is still used -- you know where from, and how often -- so you can fix your code.
|
275
281
|
|
282
|
+
---
|
283
|
+
|
284
|
+
## 💪 Optional: Global Monkey Patching
|
285
|
+
|
286
|
+
For large projects, it can be beneficial to enable deprecate_soft across the entire codebase without having to explicitly `include DeprecateSoft` or e`xtend DeprecateSoft` in each class or module.
|
287
|
+
|
288
|
+
To do this, you can globally monkey-patch `Module` by including `DeprecateSoft::GlobalMonkeyPatch`. This is **entirely optional and not enabled by default**.
|
289
|
+
|
290
|
+
Add the following to your `config/initializers/deprecate_soft.rb` initializer:
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
# config/initializers/deprecate_soft.rb
|
294
|
+
|
295
|
+
require "deprecate_soft"
|
296
|
+
require "deprecate_soft/global_monkey_patch"
|
297
|
+
|
298
|
+
# ...
|
299
|
+
|
300
|
+
class Module
|
301
|
+
include DeprecateSoft::GlobalMonkeyPatch
|
302
|
+
end
|
303
|
+
|
304
|
+
DeprecateSoft.configure do |config|
|
305
|
+
#
|
306
|
+
# ...
|
307
|
+
#
|
308
|
+
end
|
309
|
+
|
310
|
+
```
|
311
|
+
|
276
312
|
---
|
277
313
|
|
278
314
|
## 🛡 Best Practices
|
@@ -280,7 +316,7 @@ Klass#legacy_method:caller:app/jobs/cleanup_job.rb:88 → 4
|
|
280
316
|
- Use `deprecate_soft` for methods you plan to remove but want to confirm they are no longer used.
|
281
317
|
- Integrate with your observability platform for tracking.
|
282
318
|
- Review usage stats before deleting deprecated methods from your code.
|
283
|
-
-
|
319
|
+
- Always declare `deprecate_soft` **after** the method definition.
|
284
320
|
|
285
321
|
---
|
286
322
|
|
@@ -289,7 +325,6 @@ Klass#legacy_method:caller:app/jobs/cleanup_job.rb:88 → 4
|
|
289
325
|
- Make sure hooks do not raise or interfere with production behavior.
|
290
326
|
- Only use non-blocking, low-latency methods for tracking!
|
291
327
|
- Currently assumes Ruby 2.5+ (for `&.` and keyword args support).
|
292
|
-
- Currently keeps the visibility of the renamed original method the same (does not make it private).
|
293
328
|
|
294
329
|
---
|
295
330
|
|
@@ -297,9 +332,9 @@ Klass#legacy_method:caller:app/jobs/cleanup_job.rb:88 → 4
|
|
297
332
|
|
298
333
|
Feel free to open issues or pull requests if you'd like to:
|
299
334
|
|
300
|
-
-
|
335
|
+
- Request new features
|
301
336
|
- Add Railtie for automatic setup
|
302
|
-
- Add
|
337
|
+
- Add support for other backends
|
303
338
|
|
304
339
|
---
|
305
340
|
|
@@ -6,27 +6,55 @@ module DeprecateSoft
|
|
6
6
|
hidden_method_name = "#{DeprecateSoft.prefix}#{method_name}_#{DeprecateSoft.suffix}"
|
7
7
|
|
8
8
|
if is_class_method
|
9
|
-
|
9
|
+
target = context.singleton_class
|
10
|
+
|
11
|
+
return if target.method_defined?(hidden_method_name) || target.private_method_defined?(hidden_method_name)
|
10
12
|
|
11
|
-
context.
|
13
|
+
original_method = context.method(method_name)
|
14
|
+
target.define_method(hidden_method_name, original_method)
|
12
15
|
|
13
|
-
|
16
|
+
target.define_method(method_name) do |*args, &block|
|
14
17
|
full_name = "#{self.name}.#{method_name}"
|
15
|
-
|
18
|
+
|
19
|
+
begin
|
20
|
+
DeprecateSoft.before_hook&.call(full_name, message, args: args)
|
21
|
+
rescue StandardError => e
|
22
|
+
warn "DeprecateSoft.before_hook error: #{e.class} - #{e.message}"
|
23
|
+
end
|
24
|
+
|
16
25
|
result = send(hidden_method_name, *args, &block)
|
17
|
-
|
26
|
+
|
27
|
+
begin
|
28
|
+
DeprecateSoft.after_hook&.call(full_name, message, result: result)
|
29
|
+
rescue StandardError => e
|
30
|
+
warn "DeprecateSoft.after_hook error: #{e.class} - #{e.message}"
|
31
|
+
end
|
32
|
+
|
18
33
|
result
|
19
34
|
end
|
20
35
|
else
|
21
|
-
|
36
|
+
return if context.method_defined?(hidden_method_name) || context.private_method_defined?(hidden_method_name)
|
22
37
|
|
38
|
+
original_method = context.instance_method(method_name)
|
23
39
|
context.define_method(hidden_method_name, original_method)
|
24
40
|
|
25
41
|
context.define_method(method_name) do |*args, &block|
|
26
42
|
full_name = "#{self.class}##{method_name}"
|
27
|
-
|
43
|
+
|
44
|
+
begin
|
45
|
+
DeprecateSoft.before_hook&.call(full_name, message, args: args)
|
46
|
+
rescue StandardError => e
|
47
|
+
warn "DeprecateSoft.before_hook error: #{e.class} - #{e.message}"
|
48
|
+
end
|
49
|
+
|
28
50
|
result = send(hidden_method_name, *args, &block)
|
29
|
-
|
51
|
+
|
52
|
+
begin
|
53
|
+
DeprecateSoft.after_hook&.call(full_name, message, result: result)
|
54
|
+
rescue StandardError => e
|
55
|
+
warn "DeprecateSoft.after_hook error: #{e.class} - #{e.message}"
|
56
|
+
end
|
57
|
+
|
30
58
|
result
|
31
59
|
end
|
32
60
|
end
|
data/lib/deprecate_soft.rb
CHANGED
@@ -5,6 +5,20 @@ require_relative 'deprecate_soft/version'
|
|
5
5
|
require_relative 'deprecate_soft/method_wrapper'
|
6
6
|
|
7
7
|
module DeprecateSoft
|
8
|
+
def configure_base(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
base.extend(InstanceMethods)
|
11
|
+
end
|
12
|
+
module_function :configure_base
|
13
|
+
|
14
|
+
def included(base)
|
15
|
+
configure_base(base)
|
16
|
+
end
|
17
|
+
|
18
|
+
def extended(base)
|
19
|
+
configure_base(base)
|
20
|
+
end
|
21
|
+
|
8
22
|
class << self
|
9
23
|
attr_accessor :before_hook, :after_hook
|
10
24
|
attr_writer :prefix, :suffix
|
@@ -20,14 +34,6 @@ module DeprecateSoft
|
|
20
34
|
def configure
|
21
35
|
yield self
|
22
36
|
end
|
23
|
-
|
24
|
-
def included(base)
|
25
|
-
base.extend InstanceMethods
|
26
|
-
end
|
27
|
-
|
28
|
-
def extended(base)
|
29
|
-
base.extend ClassMethods
|
30
|
-
end
|
31
37
|
end
|
32
38
|
|
33
39
|
module InstanceMethods
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deprecate_soft
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tilo Sloboda
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dogstatsd-ruby
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|