summaryrefslogtreecommitdiff
path: root/lib/rubygems/core_ext/kernel_warn.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rubygems/core_ext/kernel_warn.rb')
-rw-r--r--lib/rubygems/core_ext/kernel_warn.rb45
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/rubygems/core_ext/kernel_warn.rb b/lib/rubygems/core_ext/kernel_warn.rb
new file mode 100644
index 0000000000..f806b77fab
--- /dev/null
+++ b/lib/rubygems/core_ext/kernel_warn.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Kernel
+ rubygems_path = "#{__dir__}/" # Frames to be skipped start with this path.
+
+ original_warn = instance_method(:warn)
+
+ remove_method :warn
+
+ class << self
+ remove_method :warn
+ end
+
+ module_function define_method(:warn) {|*messages, **kw|
+ unless uplevel = kw[:uplevel]
+ return original_warn.bind_call(self, *messages, **kw)
+ end
+
+ # Ensure `uplevel` fits a `long`
+ uplevel, = [uplevel].pack("l!").unpack("l!")
+
+ if uplevel >= 0
+ start = 0
+ while uplevel >= 0
+ loc, = caller_locations(start, 1)
+ unless loc
+ # No more backtrace
+ start += uplevel
+ break
+ end
+
+ start += 1
+
+ next unless path = loc.path
+ unless path.start_with?(rubygems_path, "<internal:")
+ # Non-rubygems frames
+ uplevel -= 1
+ end
+ end
+ kw[:uplevel] = start
+ end
+
+ original_warn.bind_call(self, *messages, **kw)
+ }
+end