是否可以在 proc 中看到 ruby 代码?
Posted
技术标签:
【中文标题】是否可以在 proc 中看到 ruby 代码?【英文标题】:Is it possible to see the ruby code in a proc? 【发布时间】:2013-02-08 02:10:24 【问题描述】:p = Proc.new puts 'ok'
inspect
返回内存位置:
puts p.inspect
#<Proc:0x007f9e42980b88@(irb):2>
Ruby 1.9.3
【问题讨论】:
【参考方案1】:看看sourcify gem:
proc x + y .to_source
# >> "proc (x + y) "
【讨论】:
sourcify 对 Ruby 1.9 之后的任何内容都有一个很大的警告。我对 Ruby 2.1.2 的 source_method gem 很幸运(它作为依赖项包含在我们需要它的测试基础设施中)。我这里有详细回答:***.com/questions/1675053/…【参考方案2】:你是指原始源代码还是它的字节码表示?
对于前者,您可以使用标准 Proc 方法source_location
p.source_location
=> ["test.rb", 21]
并阅读相应的代码行。
对于后者,RubyVM::InstructionSequence 及其类方法 disassemble 可能会派上用场:
irb> RubyVM::InstructionSequence.disasm p
=> "== disasm: <RubyVM::InstructionSequence:block in irb_binding@(irb)>
=====\n== catch table\n| catch type: redo st: 0000 ed: 0011 sp: 0000
cont: 0000\n| catch type: next st: 0000 ed: 0011 sp: 0000 cont:
0011\n|------------------------------------------------------------------------\n
0000 trace 1
( 1)\n0002 putself \n0003 putstring \"ok\"\n0005
send :puts, 1, nil, 8, <ic:0>\n0011 leave \n"
【讨论】:
RubyVM
是 YARV 的非标准扩展。它不是 Ruby 语言规范的一部分。 MRI 没有,Rubinius 没有,MagLev 没有,JRuby 没有,IronRuby 没有。我宁愿不依赖仅适用于单个 Ruby 实现的东西。
@JörgWMittag 所以 MRI 卡在 1.8 并且 Ruby 1.9 不是官方实现?
@JörgWMittag 另一方面,我通常同意不依赖特定的实现功能,但有时很难保持。
是的,MRI 卡在 1.8。 MRI 无意支持任何更高版本的 Ruby。 Matz 本人很久以前就停止了 MRI 的工作,他专注于 YARV(由 Koichi Sasada 编写),最近专注于 MRuby(他自己编写的 ISO Ruby 的实现)。 Ruby 1.9 不是一种实现,它是一种语言。 Ruby 1.9 没有正式的实现,有一个语言规范,每个实现该规范的实现都和其他的一样正式。其中一些实现是 YARV、MacRuby、JRuby 和 Rubinius。【参考方案3】:
不,在 Ruby 中没有办法做到这一点。
某些 Ruby 实现可能有也可能没有特定于实现的方法来获取源代码。
您也可以尝试使用Proc#source_location
查找定义Proc
的文件,然后解析该文件以查找源代码。但是如果Proc
没有在文件中定义(例如,如果它是用eval
动态定义的)或者如果源文件不再存在,那么这将不起作用,例如因为您正在运行程序的 AOT 编译版本。
所以,简短的回答是:不,没有办法。 长答案是:有些方法有时可能会起作用,也可能不会起作用,这取决于太多的因素,甚至无法开始使这项工作可靠。
这还没有考虑到Proc
s,它甚至没有 Ruby 源代码,因为它们是在本机代码中定义的。
【讨论】:
【参考方案4】:如果proc被定义到一个文件中,U可以得到proc的文件位置然后序列化它,然后反序列化后使用该位置再次回到proc
proc_location_array = proc.source_location
反序列化后:
file_name = proc_location_array[0]
line_number = proc_location_array[1]
proc_line_code = IO.readlines(file_name)[line_number - 1]
proc_hash_string = proc_line_code[proc_line_code.index("")..proc_line_code.length]
proc = eval("lambda #proc_hash_string")
【讨论】:
【参考方案5】:虽然是个老问题,但我还是想分享一下我的想法。
您可以使用 Pry gem 并最终得到如下结果:
[11] pry> p = Proc.new puts 'ok'
=> #<Proc:0x007febe00e6360@(pry):23>
[12] pry> show-source p
From: (pry)
Number of lines: 1
p = Proc.new puts 'ok'
另外,如果你想在 Rails 上下文中使用它,你可以输入:
::Kernel.binding.pry
在您的控制器或模型中,并且
- require 'pry'; binding.pry
在您的视图中,您想从哪里开始调试。
在测试中,我使用组合,首先require 'pry'
在顶部,然后::Kernel.binding.pry
在需要的地方。
参考文献:
http://pryrepl.org https://github.com/pry/pry https://github.com/pry/pry/wiki/Source-browsing【讨论】:
以上是关于是否可以在 proc 中看到 ruby 代码?的主要内容,如果未能解决你的问题,请参考以下文章