@@ -66,7 +66,7 @@ def self.replace_require(specs)
66
66
kernel_class . send ( :alias_method , :no_warning_require , :require )
67
67
kernel_class . send ( :define_method , :require ) do |name |
68
68
if message = ::Gem ::BUNDLED_GEMS . warning? ( name , specs : spec_names ) # rubocop:disable Style/HashSyntax
69
- Kernel . warn message , : uplevel => 1
69
+ Kernel . warn message , uplevel : :: Gem :: BUNDLED_GEMS . uplevel
70
70
end
71
71
kernel_class . send ( :no_warning_require , name )
72
72
end
@@ -78,6 +78,29 @@ def self.replace_require(specs)
78
78
end
79
79
end
80
80
81
+ def self . uplevel
82
+ frames_to_skip = 3
83
+ uplevel = 0
84
+ require_found = false
85
+ Thread . each_caller_location do |cl |
86
+ if frames_to_skip >= 1
87
+ frames_to_skip -= 1
88
+ next
89
+ end
90
+ uplevel += 1
91
+ if require_found
92
+ if cl . base_label != "require"
93
+ return uplevel
94
+ end
95
+ else
96
+ if cl . base_label == "require"
97
+ require_found = true
98
+ end
99
+ end
100
+ end
101
+ 1
102
+ end
103
+
81
104
def self . find_gem ( path )
82
105
if !path
83
106
return
@@ -143,29 +166,35 @@ def self.warning?(name, specs: nil)
143
166
end
144
167
145
168
def self . build_message ( gem )
146
- msg = " #{ RUBY_VERSION < SINCE [ gem ] ? "will no longer be" : "is not" } part of the default gems since Ruby #{ SINCE [ gem ] } ."
169
+ msg = " #{ RUBY_VERSION < SINCE [ gem ] ? "will no longer be" : "is not" } part of the default gems starting from Ruby #{ SINCE [ gem ] } ."
147
170
148
171
if defined? ( Bundler )
149
- msg += " Add #{ gem } to your Gemfile or gemspec."
172
+ msg += "\n You can add #{ gem } to your Gemfile or gemspec to silence this warning ."
150
173
151
- # We detect the gem name from caller_locations. We need to skip 2 frames like:
152
- # lib/ruby/3.3.0+0/bundled_gems.rb:90:in `warning?'",
153
- # lib/ruby/3.3.0+0/bundler/rubygems_integration.rb:247:in `block (2 levels) in replace_require'",
174
+ # We detect the gem name from caller_locations. First we walk until we find `require`
175
+ # then take the first frame that's not from `require`.
154
176
#
155
177
# Additionally, we need to skip Bootsnap and Zeitwerk if present, these
156
178
# gems decorate Kernel#require, so they are not really the ones issuing
157
179
# the require call users should be warned about. Those are upwards.
158
- frames_to_skip = 2
180
+ frames_to_skip = 3
159
181
location = nil
182
+ require_found = false
160
183
Thread . each_caller_location do |cl |
161
184
if frames_to_skip >= 1
162
185
frames_to_skip -= 1
163
186
next
164
187
end
165
188
166
- if cl . base_label != "require"
167
- location = cl . path
168
- break
189
+ if require_found
190
+ if cl . base_label != "require"
191
+ location = cl . path
192
+ break
193
+ end
194
+ else
195
+ if cl . base_label == "require"
196
+ require_found = true
197
+ end
169
198
end
170
199
end
171
200
@@ -178,7 +207,7 @@ def self.build_message(gem)
178
207
end
179
208
end
180
209
if caller_gem
181
- msg += " Also contact author of #{ caller_gem } to add #{ gem } into its gemspec."
210
+ msg += "\n Also please contact the author of #{ caller_gem } to request adding #{ gem } into its gemspec."
182
211
end
183
212
end
184
213
else
@@ -199,7 +228,7 @@ def message
199
228
200
229
name = path . tr ( "/" , "-" )
201
230
if !defined? ( Bundler ) && Gem ::BUNDLED_GEMS ::SINCE [ name ] && !Gem ::BUNDLED_GEMS ::WARNED [ name ]
202
- warn name + Gem ::BUNDLED_GEMS . build_message ( name )
231
+ warn name + Gem ::BUNDLED_GEMS . build_message ( name ) , uplevel : Gem :: BUNDLED_GEMS . uplevel
203
232
end
204
233
super
205
234
end
0 commit comments