【问题标题】:Why are Ruby's file related types string-based (stringly typed)?为什么 Ruby 的文件相关类型是基于字符串的(字符串类型)?
【发布时间】:2017-01-13 07:52:25
【问题描述】:

例如Dir.entries 返回一个字符串数组与包含 FileDir 实例的数组。 大多数关于 Dir 和 File 类型的方法。相比之下,这些实例是乏善可陈的。

没有Dir#foldersDir#files - 相反,我明确表示

  1. 循环遍历Dir.entries
  2. 构建路径 (File.expand_path) 每个项目
  3. 检查File.directory?

在这个目录中获取所有 .svg 文件 之类的简单用例似乎需要大量的循环/循环/检查。是我用错了 Ruby 还是 Ruby 的这个方面看起来很不像 Ruby?

【问题讨论】:

  • 嗯,这很好。假设,Dir.entries 返回了 File 对象。如果您只需要名称并正确地认为构造 File 对象会浪费 CPU 和内存怎么办?
  • 你想到的 API,它可能不在标准库中,但肯定有它的瑰宝。
  • "没有 Dir#folders 或 Dir#files" - 底层文件系统通常没有这种区别(文件和目录没有单独的列表)。因此,要仅查找目录,stdlib 方法必须执行您描述的那个循环,只是隐式的。
  • @SergioTulentsev - 是的,例如Dir.entries 可以返回字符串 + Dir#entries 返回类型化的对象。让消费者做出选择。 Ruby 中的 stdlib 方法具有以最高效的方式实现的优点 + 使客户端代码更短/更好读。
  • @Gishu:“Dir.entries 可以返回字符串 + Dir#entries 返回类型化的对象”——截至目前,我看不出原因/逻辑。如果是这样的话,我会感到非常惊讶。

标签: ruby strong-typing


【解决方案1】:

根据您的需要,FileDir 可能会很好。

当您需要链接命令并且(正确地)认为只使用带有字符串参数的类方法感觉不符合 ruby​​ 风格时,您可以使用Pathname。它是一个标准库。

示例

目录和文件

require 'pathname'

my_folder = Pathname.new('./')
dirs, files = my_folder.children.partition(&:directory?)
# dirs is now an Array of Pathnames pointing to subdirectories of my_folder
# files is now an Array of Pathnames pointing to files inside my_folder

所有 .svg 文件

如果由于某种原因可能存在带有.svg 扩展名的文件夹,您可以过滤Pathname.glob 返回的路径名:

svg_files = Pathname.glob("folder/", "*.svg").select(&:file?)

如果你想要一个特定的语法:

class Pathname
  def files
    children.select(&:file?)
  end
end

aDir = Pathname.new('folder/')
p aDir.files.find_all{ |f| f.extname == '.svg' }

迭代目录树

Pathname#find 会有所帮助。

【讨论】:

  • +1 - 虽然这是更多的心理包袱 - 学习另一种类型(我刚刚刷新了 Dir 和 File 类型 :) 和它的界面。恕我直言,可读性也受到了影响——我正在编写一个遍历文件系统的递归例程。但这行得通 - 有我需要的大部分......现在。
  • 好吧,如果您对 Dir 或 File 不满意,学习第三堂课也不错。 Pathname 有许多实例方法,将使您的工作更轻松。只是好奇:可读性在哪里受到影响?
  • 作为一个新手,我会首先搜索 Dir*/File* 类型并尝试针对它们进行编程。所以在另一个现实中,我会发现这个aDir.files.find_all{ |f| f.extName() == '.svg' } 更具可读性——反正没什么大不了的。只是违反了我对 Ruby 的POLA 的概念
  • 仅使用您的语法更新的示例。直接来自 Matz:artima.com/intv/ruby4.html “我对语言的这个特性感到惊讶,因此 Ruby 违反了最小意外原则。”等待。等待。最小意外原则不仅适用于您。最不意外的原则意味着我最不意外的原则。
  • @Gishu:“这更像是心理包袱——学习另一种类型”——嗯,路径不是文件;事物的名称不是事物本身,所以它需要是一个单独的类型。
【解决方案2】:

在您打开文件之前,它只是一个路径(字符串)。

打开所有 .svg 文件

svgs = Dir.glob(File.join('/path/to/dir', '*.svg'))

在 windows 上,文件路径无关紧要,但在所有 unixoid 系统(Linux、MacOS...)中,file.svgfile.SVG 不同

要获取所有.svg 文件和.SVG 文件,您需要 File::FNM_CASEFOLD 标志。 如果要递归获取.svg文件,则需要**/*.svg

svgs = Dir.glob('/path/to/dir/**/*.svg', File::FNM_CASEFOLD)

如果您希望目录以.svg 结尾,则将它们过滤掉

svgs.reject! { |path| File.directory?(path) }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-21
    • 1970-01-01
    • 2019-11-06
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 2021-06-23
    相关资源
    最近更新 更多