如何获取Ruby Proc/Lambda源码?优化Benchmark.ips显示内容
问题:Benchmark.ips自定义参数时无法显示期望的方法名
尝试执行的代码
Benchmark.ips(-> { add }, -> { sub })
当前实现
def Benchmark.ips(*reports, &block) if reports.any? super() do |x| reports.each do |report| x.report(report.to_s) { report.call } end end else super end end
出现的问题
当前输出会显示Proc对象的默认字符串表示,而不是期望的add和sub:
#<Proc:0x0000000102d0d3f8 a.rb:61 (lambda)> 1.810M i/100ms
需求
希望在x.report的名称位置显示对应的方法名add和sub,替代当前的Proc对象字符串。
解决方案
Ruby的Proc/lambda本身不会记录关联的方法名称,所以需要调整参数传递方式或通过解析代码来实现需求:
方案1:传递名称与Proc的哈希(推荐)
这种方式最可靠,直接明确指定每个基准测试的名称:
# 修改调用代码 Benchmark.ips(add: -> { add }, sub: -> { sub }) # 修改实现代码 def Benchmark.ips(reports = {}, &block) if reports.is_a?(Hash) && !reports.empty? super() do |x| reports.each do |name, report| x.report(name.to_s) { report.call } end end else super end end
方案2:解析Lambda源代码(仅适用于简单场景)
如果必须保留原调用方式,可以尝试读取Lambda的源代码来提取方法名,但这种方式依赖固定的代码格式:
def Benchmark.ips(*reports, &block) if reports.any? super() do |x| reports.each do |report| file, line = report.source_location next unless file && line # 读取对应行的代码并提取方法名 code_line = File.readlines(file)[line - 1].strip method_name = if code_line =~ /->\s*\{\s*(\w+)\s*\}/ $1 else report.to_s end x.report(method_name) { report.call } end end else super end end
注意:如果Lambda内部有复杂逻辑(比如多行代码、参数传递),这个解析逻辑会失效,仅适合-> { method }这种简单格式。
内容的提问来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

