Skip to content

Commit 6d5beae

Browse files
authored
Merge pull request #3 from tilo/towards-1.2.0
Towards 1.2.0
2 parents 05eb6c4 + e969293 commit 6d5beae

14 files changed

+654
-439
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,3 @@ jobs:
3838
with:
3939
token: ${{ secrets.CODECOV_TOKEN }}
4040
files: coverage/.resultset.json
41-
verbose: true

.rubocop.yml

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
AllCops:
22
TargetRubyVersion: 2.5 # purposely an old Ruby version
33

4-
Style/StringLiterals:
5-
EnforcedStyle: single_quotes
4+
Layout/LineLength:
5+
Max: 180
66

7-
Style/StringLiteralsInInterpolation:
8-
EnforcedStyle: single_quotes
7+
Lint/ConstantDefinitionInBlock:
8+
Enabled: false
9+
10+
Lint/UnusedBlockArgument:
11+
Enabled: false
912

1013
Metrics/AbcSize:
1114
Enabled: false
@@ -22,9 +25,6 @@ Metrics/CyclomaticComplexity:
2225
Metrics/MethodLength:
2326
Enabled: false
2427

25-
Lint/UnusedBlockArgument:
26-
Enabled: false
27-
2828
Naming/MethodParameterName:
2929
Enabled: false
3030

@@ -34,8 +34,20 @@ Style/SafeNavigation:
3434
Style/Documentation:
3535
Enabled: false
3636

37+
Style/IfUnlessModifier:
38+
Enabled: false
39+
3740
Style/RedundantSelf:
3841
Enabled: false
3942

4043
Style/SingleLineMethods:
4144
Enabled: false
45+
46+
Style/StringLiterals:
47+
EnforcedStyle: single_quotes
48+
49+
Style/StringLiteralsInInterpolation:
50+
EnforcedStyle: single_quotes
51+
52+
Style/TrivialAccessors:
53+
Enabled: false

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11

22
## 📝 DepracateSoft Change Log
33

4+
## [1.2.0] - 2025-04-05
5+
### ✨ Added Support
6+
- improving handling of class methods
7+
- added deprecate_class_soft for class methods. Fixed [Issue #1](https://github.com/tilo/deprecate_soft/issues/1)
8+
- support to define the method after the declaration
9+
### 🛠️ Internals
10+
- stream-lined include DeprecateSoft
11+
### 📐 Deliberate Limitations
12+
- Class methods need to be defined via `def self.method`, not in `class << self` blocks.
13+
Simply move the to-be-deprecated method out of the `self << class` and declare it via `self.method_name`.
14+
This also makes the to be deleted method stand out more.
15+
416
## [1.1.0] - 2025-03-29
517
### ✨ Added Support
618
- Errors in `before_hook` / `after_hook` do not prevent method execution.

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ Declare `deprecate_soft` **after** the method definition.
5858

5959
### For Instance Methods:
6060

61+
use `deprecate_soft`
62+
6163
```ruby
6264
class MyService
6365
include DeprecateSoft
@@ -74,15 +76,17 @@ MyService.new.deprecated_method(1, 2) # will exercise the tracking hooks
7476

7577
### For Class Methods:
7678

79+
use `deprecate_class_soft`
80+
7781
```ruby
7882
class MyService
79-
extend DeprecateSoft
83+
include DeprecateSoft
8084

8185
def self.deprecated_method(a, b)
8286
puts "doing something with #{a} and #{b}"
8387
end
8488

85-
deprecate_soft :deprecated_method, "will be removed"
89+
deprecate_class_soft :deprecated_method, "will be removed" # ⚠️
8690
end
8791

8892
MyService.deprecated_method(1, 2) # will exercise the tracking hooks
@@ -330,6 +334,9 @@ end
330334
- Make sure hooks do not raise or interfere with production behavior.
331335
- Only use non-blocking, low-latency methods for tracking!
332336
- Currently assumes Ruby 2.5+ (for `&.` and keyword args support).
337+
- Class methods need to be defined via `def self.method`, not in `class << self` blocks.
338+
Simply move the to-be-deprecated method out of the `self << class` and declare it via `self.method_name`.
339+
This also makes the to be deleted method stand out more.
333340

334341
---
335342

lib/deprecate_soft.rb

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
11
# frozen_string_literal: true
22

3-
require_relative 'deprecate_soft/version'
4-
5-
require_relative 'deprecate_soft/method_wrapper'
3+
# require all files under lib/deprecate_soft
4+
Dir[File.join(__dir__, 'deprecate_soft', '*.rb')].sort.each do |file|
5+
require file
6+
end
67

78
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-
229
class << self
2310
attr_accessor :before_hook, :after_hook
2411
attr_writer :prefix, :suffix
@@ -34,23 +21,58 @@ def suffix
3421
def configure
3522
yield self
3623
end
37-
end
3824

39-
module InstanceMethods
40-
def deprecate_soft(method_name, message)
41-
# protect against declaring deprecate_soft before method is defined
42-
return unless method_defined?(method_name) || private_method_defined?(method_name)
25+
def prefixed_name(method_name)
26+
"#{prefix}#{method_name}_#{suffix}".to_sym
27+
end
28+
29+
def included(base)
30+
base.extend(ClassMethods)
4331

44-
DeprecateSoft::MethodWrapper.wrap_method(self, method_name, message, is_class_method: false)
32+
base.define_singleton_method(:method_added) do |method_name|
33+
pending = base.instance_variable_get(:@__pending_soft_wraps)
34+
if pending&.key?(method_name)
35+
DeprecateSoft::MethodWrapper.wrap_method(base, method_name, pending.delete(method_name), is_class_method: false)
36+
end
37+
super(method_name) if defined?(super)
38+
end
39+
40+
base.singleton_class.define_method(:singleton_method_added) do |method_name|
41+
pending = instance_variable_get(:@_pending_soft_wraps)
42+
if pending&.key?(method_name)
43+
DeprecateSoft::MethodWrapper.wrap_method(base, method_name, pending.delete(method_name), is_class_method: true)
44+
end
45+
super(method_name) if defined?(super)
46+
end
4547
end
4648
end
4749

4850
module ClassMethods
49-
def deprecate_soft(method_name, message)
50-
# protect against declaring deprecate_soft before method is defined
51-
return unless singleton_class.method_defined?(method_name) || singleton_class.private_method_defined?(method_name)
51+
def deprecate_soft(method_name, message = nil)
52+
hidden = DeprecateSoft.prefixed_name(method_name)
53+
54+
if method_defined?(method_name) || private_method_defined?(method_name)
55+
return if method_defined?(hidden) || private_method_defined?(hidden)
56+
57+
DeprecateSoft::MethodWrapper.wrap_method(self, method_name, message, is_class_method: false)
58+
else
59+
@__pending_soft_wraps ||= {}
60+
@__pending_soft_wraps[method_name] = message
61+
end
62+
end
63+
64+
def deprecate_class_soft(method_name, message = nil)
65+
hidden = DeprecateSoft.prefixed_name(method_name)
66+
target = singleton_class
67+
68+
if target.method_defined?(method_name) || target.private_method_defined?(method_name)
69+
return if target.method_defined?(hidden) || target.private_method_defined?(hidden)
5270

53-
DeprecateSoft::MethodWrapper.wrap_method(self, method_name, message, is_class_method: true)
71+
DeprecateSoft::MethodWrapper.wrap_method(self, method_name, message, is_class_method: true)
72+
else
73+
@_pending_soft_wraps ||= {}
74+
@_pending_soft_wraps[method_name] = message
75+
end
5476
end
5577
end
5678
end

lib/deprecate_soft/global_monkey_patch.rb

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
module DeprecateSoft
44
module GlobalMonkeyPatch
55
def deprecate_soft(method_name, message)
6-
if self.singleton_class.method_defined?(method_name) || self.singleton_class.private_method_defined?(method_name)
7-
# Class method
8-
DeprecateSoft::MethodWrapper.wrap_method(self, method_name, message, is_class_method: true)
9-
elsif self.instance_methods.include?(method_name) || self.private_instance_methods.include?(method_name)
10-
# Instance method
11-
DeprecateSoft::MethodWrapper.wrap_method(self, method_name, message, is_class_method: false)
12-
else # rubocop:disable Style/EmptyElse
13-
# protect against declaring deprecate_soft before method is defined
14-
#
15-
# Do nothing — fail-safe in production
16-
end
6+
extend DeprecateSoft::ClassMethods unless is_a?(DeprecateSoft::ClassMethods)
7+
deprecate_soft(method_name, message)
8+
end
9+
10+
def deprecate_class_soft(method_name, message = nil)
11+
extend DeprecateSoft::ClassMethods unless is_a?(DeprecateSoft::ClassMethods)
12+
deprecate_class_soft(method_name, message)
1713
end
1814
end
1915
end

lib/deprecate_soft/method_wrapper.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ def self.wrap_method(context, method_name, message, is_class_method:)
1414
target.define_method(hidden_method_name, original_method)
1515

1616
target.define_method(method_name) do |*args, &block|
17-
full_name = "#{self.name}.#{method_name}"
17+
klass_name = self.class.name || self.class.to_s
18+
full_name = "#{klass_name}.#{method_name}"
1819

1920
begin
2021
DeprecateSoft.before_hook&.call(full_name, message, args: args)
@@ -39,7 +40,8 @@ def self.wrap_method(context, method_name, message, is_class_method:)
3940
context.define_method(hidden_method_name, original_method)
4041

4142
context.define_method(method_name) do |*args, &block|
42-
full_name = "#{self.class}##{method_name}"
43+
klass_name = self.class.name || self.to_s
44+
full_name = "#{klass_name}.#{method_name}"
4345

4446
begin
4547
DeprecateSoft.before_hook&.call(full_name, message, args: args)

lib/deprecate_soft/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module DeprecateSoft
4-
VERSION = '1.1.0'
4+
VERSION = '1.2.0'
55
end

0 commit comments

Comments
 (0)