8

我有一个 gem,里面有这样的代码:

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.txt如果它在同一个目录中,它会起作用,main.rb但如果它在一个目录中,它就不会起作用。为了解决这个问题,我添加了一个名为relative_toin的可选参数read()。这需要一个绝对路径,所以上面可能需要:

require 'mygem'

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

这很好用,但我认为它有点难看。有没有办法让班级知道read()正在调用什么文件并根据它计算出路径?

4

5 回答 5

4

有一个有趣的图书馆——我告诉过你它是私人的。人们可以用它来保护他们的方法不被外部调用。代码找到调用方方法的文件并将其删除。使用此行找到罪犯:

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

于 2013-02-16T09:57:48.213 回答
2

好吧,您可以使用 caller,而且比其他人所说的更可靠。

在您的 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__,否则如果他们更改工作目录,您将无能为力。

于 2013-02-17T22:23:01.843 回答
1

您也可以检查来电者

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)。此外,如果调用者路径打算包含冒号,则应该更准确地调整上面的正则表达式。

于 2013-02-08T15:41:56.460 回答
1

接受文件路径字符串作为参数。转换为路径名对象。检查路径是否是相对的。如果是,则转换为绝对值。

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

您可以使此代码更简洁(不那么冗长)。

于 2013-02-14T07:47:18.020 回答
1

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

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

附带说明一下,考虑添加一个块形式的方法,在屈服后关闭文件。在当前的形式中,您强制客户使用ensure.

于 2013-02-13T05:12:16.663 回答