@@ -66,7 +66,7 @@ def self.replace_require(specs)
6666 kernel_class . send ( :alias_method , :no_warning_require , :require )
6767 kernel_class . send ( :define_method , :require ) do |name |
6868 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
7070 end
7171 kernel_class . send ( :no_warning_require , name )
7272 end
@@ -78,6 +78,29 @@ def self.replace_require(specs)
7878 end
7979 end
8080
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+
81104 def self . find_gem ( path )
82105 if !path
83106 return
@@ -143,29 +166,35 @@ def self.warning?(name, specs: nil)
143166 end
144167
145168 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 ] } ."
147170
148171 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 ."
150173
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`.
154176 #
155177 # Additionally, we need to skip Bootsnap and Zeitwerk if present, these
156178 # gems decorate Kernel#require, so they are not really the ones issuing
157179 # the require call users should be warned about. Those are upwards.
158- frames_to_skip = 2
180+ frames_to_skip = 3
159181 location = nil
182+ require_found = false
160183 Thread . each_caller_location do |cl |
161184 if frames_to_skip >= 1
162185 frames_to_skip -= 1
163186 next
164187 end
165188
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
169198 end
170199 end
171200
@@ -178,7 +207,7 @@ def self.build_message(gem)
178207 end
179208 end
180209 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."
182211 end
183212 end
184213 else
@@ -199,7 +228,7 @@ def message
199228
200229 name = path . tr ( "/" , "-" )
201230 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
203232 end
204233 super
205234 end
0 commit comments