gpt4 book ai didi

ruby - 如何在 Ruby 中查找所有引用的文件

转载 作者:太空宇宙 更新时间:2023-11-03 16:31:04 24 4
gpt4 key购买 nike

我想检测 Ruby 文件直接引用的所有文件以用于文档目的。阅读基本要求列表是不完整的,因为有些文件是通过传递导入的,而另一些文件是导入但从未使用过的。例如:

a.rb:

require 'b'
require 'e'
class A; end
B.new; C.new

b.rb:

require 'c'
require 'd'
class B; end
C.new; D.new

c.rb:
class C; end

(d.rb and e.rb are just like c.rb)

然后我想为 a.rb 获取的列表是 b.rb, c.rb。没有 D 或 E,因为它们没有被直接引用。希望这是有道理的!

最佳答案

所以这里对“使用”的含义有些模糊。显然使用了 d,因为 b.rb(也被使用)在最后调用了 D.new。如果我们警告“使用”的意思是“代码是从该文件执行的,而不是在 require 过程中”,那么下面的代码是一个结束,因为我可以在 ruby​​ 1.9.3 上使用

require 'set'
def analyze(filename)
require_depth = 0
files = Set.new
set_trace_func( lambda do |event, file, line, id, binding, classname|
case event
when 'call'then require_depth += 1 if id == :require && classname == Kernel
when 'return' then require_depth -= 1 if id == :require && classname == Kernel
when 'line'
files << file if require_depth == 0
end
end)
load filename
set_trace_func nil
files.reject {|f| f == __FILE__ || f =~ %r{/lib/ruby/site_ruby}}
end

您可以通过运行 analyse 'a.rb' 来使用它(假设所有涉及的文件都在加载路径上)。它所做的是使用 ruby​​ 的 set_trace_func 来监听正在发生的事情。第一部分粗略地试图忽略调用 require 期间发生的所有事情。然后我们累积每行执行的 ruby​​ 的文件名。最后一行只是清除垃圾(例如补丁需要的 ruby​​gems 文件)。

这对于测试示例实际上不起作用:当 B.new 运行时,实际上没有执行 b.rb 中的代码行。但是,如果 B(和 C、D 等)具有初始化方法(或调用的某行代码),那么您应该会得到所需的结果。这是非常简单的东西,可能会被各种各样的东西愚弄。特别是如果你在(比如说)B 上调用一个方法,但是那个方法的实现不在 b.rb 中(例如,一个用 attr_accessor 定义的访问器)那么 b.rb 就不会被记录

您也许可以更好地使用 call 事件,但我认为使用 set_trace_func 不能做更多的事情。

如果您使用的是 ruby​​ 2.0,则可以使用 TracePoint,它是 set_trace_func 的替代品。它的语义略有不同,特别是当我们跟踪方法调用时,更容易获得调用它的类

require 'set'
def analyze(filename)
require_depth = 0
files = Set.new
classes_to_files = {}
trace = TracePoint.new(:call, :line, :return, :c_call, :class) do |tp|
case tp.event
when :class
classes_to_files[tp.self] = tp.path
when :call, :c_call then
if tp.method_id == :require && tp.defined_class == Kernel
require_depth += 1
else
if require_depth == 0
if path = classes_to_files[tp.self] || classes_to_files[tp.self.class]
files << path
end
end
end
when :return then require_depth -= 1 if tp.method_id == :require && tp.defined_class == Kernel
when :line
if require_depth == 0
files << tp.path
end
end
end

trace.enable
load filename
trace.disable
files.reject {|f| f == __FILE__ || f =~ %r{/lib/ruby/site_ruby}}
end

确实为测试示例返回 a,b,c。它仍然受到基本限制,即它只知道实际执行的代码。

关于ruby - 如何在 Ruby 中查找所有引用的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15854471/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com