Project

General

Profile

Feature #20335

Updated by byroot (Jean Boussier) 9 months ago

`Thread.each_caller_location` was added to Ruby 3.2 as part of [Feature #16663] and is a very useful API for emitting warnings with a proper source location and similar use cases. 

 However in many of the cases where I used it, or seen it used, it was needed to skip the first, or a couple frames: 

 Examples: 

 Sorbet: https://github.com/Shopify/sorbet/blob/b27a14c247ace7cabdf0f348bfb11fdf0b7e9ab4/gems/sorbet-runtime/lib/types/private/caller_utils.rb#L6-L18 

 ```ruby 
     def self.find_caller 
       skiped_first = false 
       Thread.each_caller_location do |loc| 
         unless skiped_first 
           skiped_first = true 
           next 
         end 

         next if loc.path&.start_with?("<internal:") 

         return loc if yield(loc) 
       end 
       nil 
     end 
 ``` 

 @fxn 's @fxn's PR: https://github.com/ruby/ruby/blob/9c2e686719a5a4df5ea0b8a3b6a373ca6003c229/lib/bundled_gems.rb#L140-L146 

 ```ruby 
       frames_to_skip = 2 
       location = nil 
       Thread.each_caller_location do |cl| 
         if frames_to_skip >= 1 
           frames_to_skip -= 1 
           next 
         end 
       # snipp... 

 ``` 

 ### Proposal 

 I think it would be very useful if `Thread.each_caller_location` accepted the same arguments as `caller` and `caller_locations`: 

 ```ruby 
 #each_caller_location(start = 1, length = nil) 
 #each_caller_location(range) 
 ``` 

 @jeremyevans0 what do you think? 

Back