这是一个深奥的请求,对我来说只是理论上的兴趣(换句话说,我没有在生产代码中使用它)。我想知道在运行ruby程序时是否有可能找出所涉及的所有文件。也就是说,文件require
d在执行期间由所述程序执行(或者以其他方式涉及,例如在程序中途由Rails autoload
编辑)。
我知道可以使用ObjectSpace
并循环遍历该对象,除了File
及其后代以外的所有对象,当我禁用垃圾收集时,我在此方法上取得了部分成功(否则列表会收缩)在随机时间,可以理解)。但是,在程序开始时执行此操作会忽略其中间所需的那些文件,因此我可以在最后运行相同的代码,并获得所述文件的并集?
答案 0 :(得分:3)
在Linux上,您可以使用lsof
:
puts `lsof -a -p #{Process.pid}`
它为您提供当前进程打开的文件保持。
该列表远未完成:一旦执行此行,就会读取,解析,执行和关闭许多文件。
当lsof
扫描打开的文件时,它们不再出现在列表中。
strace
(也在Linux上)是一个很棒的工具,可以实现您想要实现的目标(请参阅此thread)。它会提供很多(可能太多)信息:
strace -e trace=open -o opened_files.txt ruby hello_world.rb
#=> Hello world
opened_files.txt
现在以:
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/tls/x86_64/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/tls/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/x86_64/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libruby.so.2.3", O_RDONLY|O_CLOEXEC) = 3
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libpthread.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/home/ricou/.rvm/rubies/ruby-2.3.1/lib/libgmp.so.10", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
....
“Hello World”脚本有571行,“rails runner hello_world.rb”脚本有112302(!)。
输出文件有许多“ENOENT(没有这样的文件或目录)”行,所以你可能想要解析和过滤它。
对于macOS和其他* nix,应该有dtrace
。
答案 1 :(得分:2)
REQUIRE_FILE = ENV.fetch('REQUIRE_FILE', '/tmp/requires.txt')
File.open(REQUIRE_FILE, 'w')
Kernel.module_eval do
alias_method :require_without_benchmark, :require
def require(name)
start = Time.now
begin
require_without_benchmark(name)
ensure
time = Time.now - start
File.write(REQUIRE_FILE, [name, time.to_f].join(',').concat("\n"), mode: 'a')
end
end
end
然后将您的程序运行为:
ruby -r ./require-benchmark.rb program.rb
答案 2 :(得分:1)
有关所需文件,请参阅How do I get a list of files that have been `required` in Ruby?。 对于gem的所有依赖项,请参阅How do I find out all the dependencies of a gem?
常量$LOADED_FEATURES
包含所有文件的数组,其中包含带有require的路径,不仅包括gem本身,还包含所有涉及的文件。
在脚本末尾尝试$LOADED_FEATURES.dup.uniq
。
对于File打开的普通文件,你可以用KARASZI在答案中显示的方式覆盖IO.open
和/或File.open
以及姐妹方法read,binread等。