获取实例化类ruby的文件目录

时间:2013-02-08 12:17:18

标签: ruby file-io

我有一个像这样的代码的宝石:

def read(file)
    @file = File.new file, "r"
end

现在的问题是,你有一个像这样的目录结构:

app/main.rb
app/templates/example.txt

main.rb包含以下代码:

require 'mygem'

example = MyGem.read('templates/example.txt')

它出现了File Not Found: templates/example.txt。如果example.txtmain.rb位于同一目录中,则会起作用,但如果它位于目录中则不行。为了解决这个问题,我在relative_to中添加了一个名为read()的可选参数。这需要一个绝对路径,所以上面可能需要:

require 'mygem'

example = MyGem.read('templates/example.txt', File.dirname(__FILE__))

工作正常,但我认为这有点难看。无论如何都要这样做,以便类知道调用哪个文件read()并根据它来计算路径?

5 个答案:

答案 0 :(得分:4)

有一个有趣的图书馆 - i told you it was private。人们可以用它从外面调用来保护他们的方法。代码找到调用方法的文件并将其删除。使用以下行找到罪犯

offender = caller[0].split(':')[0]

我猜您可以在MyGem.read代码中使用它:

def read( file )
  fpath = Pathname.new(file)
  if fpath.relative?
    offender = caller[0].split(':')[0]
    fpath = File.join( File.dirname( offender ), file )
  end
  @file = File.new( fpath, "r" )
end

这样你就可以使用相对于你的Mygem调用者而不是pwd的路径。正是您在app/main.rb

中尝试的方式

答案 1 :(得分:2)

嗯,你可以使用来电,比其他人说的更可靠。

在您的gem文件中,在任何类或模块之外,请输入:

c = caller
req_file = nil
c.each do |s|
  if(s =~ /(require|require_relative)/)
    req_file = File.dirname(File.expand_path(s.split(':')[0])) #Does not work for filepaths with colons!
    break
  end
end
REQUIRING_FILE_PATH = req_file

这将在90%的时间内工作,除非要求脚本执行Dir.chdir。 File.expand_path依赖于此。我担心,除非你的要求者通过__FILE__,否则如果他们改变了工作目的,你就无能为力。

答案 2 :(得分:1)

您也可以查看caller

def read(file)
  if /^(?<file>.+?):.*?/ =~ caller(1).first
    caller_dir, caller_file = Pathname.new(Regexp.last_match[:file]).split
    file_with_path = File.join caller_dir, file
    @file = File.new "#{file_with_path}", "r"
  end
end

我不建议您这样做(由于caller(1),上面的代码会间接调用,因为请参阅caller上的文档。此外,如果调用者路径旨在包含冒号,则应更准确地调整上述正则表达式。

答案 3 :(得分:1)

这应该适用于典型用途(我不确定它对间接使用的抵抗力,如madusobwa above所述):

def read_relative(file)
  @file = File.new File.join(File.dirname(caller.first), file)
end

另外,请考虑添加方法的块形式,以便在屈服后关闭文件。在当前形式中,您迫使客户使用ensure包装他们对宝石的使用。

答案 4 :(得分:1)

接受文件路径String作为参数。转换为Pathname对象。检查路径是否相对。如果是,则转换为绝对。

def read(file)
  fpath = Pathname.new(file)
  if fpath.relative?
    fpath = File.expand_path(File.join(File.dirname(__FILE__),file))
  end
  @file = File.new(fpath,"r")
end

您可以使此代码更简洁(更简洁)。