在Ruby中,我如何解释(扩展)相对于目录的glob?

时间:2015-08-06 15:48:16

标签: ruby glob

更广泛的上下文:区分大小写的文件系统上的不区分大小写的文件名

给定目录的路径(作为字符串,可能相对于当前工作目录或绝对路径),我想打开一个特定文件。我知道文件的文件名,除了它的情况。 (可能是TASKDATA.XMLTaskData.xml甚至tAsKdAtA.xMl。)

受到the accepted answer启发Open a file case-insensitively in Ruby under Linux的启发,我已经想出了这个小模块来生成一个用于匹配文件名称的glob:

module Utils
  def self.case_insensitive_glob_string(string)
    string.each_char.map do |c|
      cased = c.upcase != c.downcase
      cased ? "[#{c.upcase}#{c.downcase}]" : c
    end.join
  end
end

就我的具体情况而言,我打电话给

 Utils.case_insensitive_glob_string('taskdata.xml')

并且会得到

'[Tt][Aa][Ss][Kk][Dd][Aa][Tt][Aa].[Xx][Mm][Ll]'

特定上下文:相对于dir≠pwd

的glob

现在我必须展开glob,即将它与给定目录中的实际文件进行匹配。不幸的是,Dir.glob(...)似乎没有一个参数来传递相对于应该扩展glob的目录(' s路径)。直观地说,创建一个Dir对象并处理glob会对我有意义:

d = Dir.new(directory_path)
# => #<Dir:/the/directory>

filename = d.glob(Utils.case_insensitive_glob_string('taskdata.xml')).first() # I wish ...
# NoMethodError: undefined method `glob' for #<Dir:/the/directory>

...但glob仅作为类方法存在,而不是作为实例方法存在。 (任何人都知道为什么这么多Dir的方法能够完全理解相对特定的目录? )

所以看起来我有两个选择:

  1. 将当前工作目录更改为给定目录

  2. 结合目录路径
  3. 扩展文件名&amp; glob

    第一个选项很简单:使用Dir.chdir。但是因为这是宝石,我不想弄乱我的宝石用户的环境,我回避它。 (与块概要一起使用时,可能会比我手动(或不)重置工作目录时好一些。)

    第二个选项看起来很简单。只需做

    taskdata_xml_name_glob = Utils.case_insensitive_glob_string('taskdata.xml')
    taskdata_xml_path_glob = File.join(directory_path, taskdata_xml_name_glob)
    filename = Dir.glob(taskdata_xml_path_glob).first()
    

    ,对吗?几乎。当directory_path包含在globs中具有特殊含义的字符时,当我只想对文件名进行全局扩展时,它们将错误地展开。这不太可能,但由于Gem用户提供了路径,无论如何我都要考虑它。

    问题

    我应该在使用文件名glob directory_path之前逃离File.join吗?如果是这样,是否有设施可以做到这一点,还是我必须自己编写转义函数?

    或者我应该使用不同的方法(无论是chdir还是其他不同的方法)?

1 个答案:

答案 0 :(得分:2)

如果我实现了这种行为,我会过滤一个由Dir#entries返回的数组:

Dir.entries("#{target}").select { |f| f =~ /\A#{filename}\z/i }

请注意,在unix平台上,...条目也会列出,但在第二步中不太可能匹配它们。此外,文件名可能应使用Regexp.escape转义:

Dir.entries("#{target}").select { |f| f =~ /\A#{Regexp.escape(filename)}\z/i }