14
p = Proc.new{ puts 'ok' }

是否可以在 proc 中看到 ruby​​ 代码?

inspect返回内存位置:

puts p.inspect
#<Proc:0x007f9e42980b88@(irb):2>

红宝石 1.9.3

4

5 回答 5

9

看一下sourcify gem:

proc { x + y }.to_source
# >> "proc { (x + y) }"
于 2013-02-22T12:53:47.647 回答
7

你的意思是原始源代码还是它的字节码表示?

对于前者,您可以使用标准 Proc 方法source_location

p.source_location
=> ["test.rb", 21]

并阅读相应的代码行。

对于后者,RubyVM::InstructionSequence 及其类方法反汇编可能会派上用场:

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"
于 2013-02-22T13:07:00.517 回答
5

不,在 Ruby 中没有办法做到这一点。

一些 Ruby 实现可能有也可能没有特定于实现的方法来获取源代码。

您也可以尝试使用Proc#source_location查找Proc定义 的文件,然后解析该文件以查找源代码。但是,如果Proc没有在文件中定义(例如,如果它是用 动态定义的eval)或者源文件不再存在,例如因为您正在运行程序的 AOT 编译版本,这将不起作用。

所以,简短的回答是:不,没有办法。长答案是:有些方法有时可能会或可能不会起作用,这取决于太多的因素,甚至无法开始使这项工作可靠。

这甚至没有考虑Procs 甚至没有Ruby 源代码,因为它们是在本机代码中定义的。

于 2013-02-22T13:29:48.873 回答
2

如果proc被定义到一个文件中,U可以获取proc的文件位置然后序列化它,然后在反序列化后使用该位置再次回到proc

proc_location_array = proc.source_location

反序列化后:

文件名 = 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}")

于 2017-04-11T17:29:46.773 回答
2

虽然是一个老问题,但我还是想分享我的想法。

您可以使用 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在需要的地方。

参考:

于 2018-10-26T22:55:58.557 回答