当前位置:  开发笔记 > 编程语言 > 正文

Ruby File ::目录?问题

如何解决《RubyFile::目录?问题》经验,为你挑选了2个好方法。

我对红宝石很新,但到目前为止非常享受它.有些事情给了我一些麻烦,以下也不例外.

我在这里要做的是通过对"Dir"进行子类化来创建一种"超级目录".我添加了一个名为'subdirs'的方法,用于列出目录对象的文件,如果文件本身是目录,则将它们推送到数组中.问题是,我的测试(File.directory?)的结果很奇怪 - 这是我的方法代码:

  def subdirs
    subdirs = Array.new
    self.each do |x|
      puts "Evaluating file: #{x}"
      if File.directory?(x)
        puts "This file (#{x}) was considered a directory by File.directory?"
        subdirs.push(x)
        #yield(x) if block_given?
      end
    end
    return subdirs
  end

奇怪的是,即使我选择的目录中有很多目录("/ tmp") - 这个调用的结果只列出"." 和"......"

puts "Testing new Directory custom class: FileOps/DirClass"

nd   = Directory.new("/tmp")
subs = nd.subdirs

结果如下:

Evaluating file: mapping-root
Evaluating file: orbit-jvxml
Evaluating file: custom-directory
Evaluating file: keyring-9x4JhZ
Evaluating file: orbit-root
Evaluating file: .
This file (.) was considered a directory by File.directory?
Evaluating file: .gdmFDB11U
Evaluating file: .X0-lock
Evaluating file: hsperfdata_mishii
Evaluating file: .X11-unix
Evaluating file: .gdm_socket
Evaluating file: ..
This file (..) was considered a directory by File.directory?
Evaluating file: .font-unix
Evaluating file: .ICE-unix
Evaluating file: ssh-eqOnXK2441
Evaluating file: vesystems-package
Evaluating file: mapping-jvxml
Evaluating file: hsperfdata_tomcat

Mark Westlin.. 17

你是从内部执行脚本/tmp吗?我的猜测(我没有试过)是,File.directory?(x)正在测试,看看是否有在当前目录下一个名为X的目录-所以,如果你从另一个目录中运行这个,你一定会找到...而不是其他目录.

尝试File.directory?(x)改为File.directory?("#{path}/#{x}").



1> Mark Westlin..:

你是从内部执行脚本/tmp吗?我的猜测(我没有试过)是,File.directory?(x)正在测试,看看是否有在当前目录下一个名为X的目录-所以,如果你从另一个目录中运行这个,你一定会找到...而不是其他目录.

尝试File.directory?(x)改为File.directory?("#{path}/#{x}").


马克,谢谢 - 这是绝对正确的.我原以为曾经实例化为特定目录的目录对象会假设该位置..但我所知道的任何事情都不会这样,我不知道为什么我认为这也是这样.哦,好吧:0)谢谢!

2> Jörg W Mitta..:

马克韦斯特林已经回答了你当前的问题,但既然你提到你是Ruby的新手,这里有几个其他风格的建议:

def subdirs
  subdirs = Array.new

通常最好在可能的情况下使用文字语法,因此表达这一点的常用方法是subdirs = [].

  self.each do |x|

self是Ruby中的隐式接收器,所以你可以把它关掉.(毕竟这不是Python.)然而,代码的主要目的是通信,所以如果你相信,这会更好地传达你的意图,留下它.

说到沟通:x除非你在谈论笛卡尔坐标系中的点,否则它不是一个非常交流的名字.怎么样file,或者如果你对Unix目标也是文件的概念感到不舒服,那就更中立了entry?(实际上,最好的可能是path,但我们很快就会看到这可能会让人感到困惑.)

我的第三个建议实际上是个人的偏好是与一般的Ruby风格:常见的Ruby风格决定了一个行块分隔与{/ }和多块分隔的do/ end,就像你一样.我不喜欢这样,因为它是一种任意的区别,没有任何意义.(还记得"沟通"的事情吗?)所以,我实际上做的事情是不同的:如果块本质上是命令性的,例如,改变一些全局状态,我使用关键字(因为块实际上是do一些工作),如果块本质上是功能性的,只返回一个新对象,我更喜欢使用大括号(因为它们看起来很好数学).所以,在这种情况下,我会使用大括号.

    if File.directory?(x)

正如Mark已经解释的那样,你需要做类似这样的File.directory?(File.join(path, entry))事情,其中Dir#path一个Dir类的公共属性返回Dir.new初始化的路径.

在这里你还看到,为什么我们没有使用path块参数的名称.否则我们需要写File.directory?(File.join(self.path, path)).

      subdirs.push(x)

将元素附加到数组,或者确实在Ruby中附加任何东西的规范方法是<<运算符.所以,这应该读subdirs << entry.

Array#push是别名Array#<<,主要用于让您使用Array堆栈(与之结合使用Array#pop).

    end
  end
  return subdirs

这是我的个人风格和常见的Ruby风格之间的另一个脱节:在Ruby中,如果没有显式return,返回值只是最后一个表达式的值.这意味着,您可以省略return关键字和常见的Ruby样式.但是,我更喜欢使用类似于块分隔符return的方法:用于本质上是功能性的方法(因为它们实际上"返回"一个值)而不return用于命令式方法(因为它们的实际返回值不是return关键字后面的内容),但他们对环境有什么副作用).所以,就像你一样,我会return在这里使用一个关键字,尽管有共同的风格.

习惯上,通过空行将方法体的其余部分的返回值分开.(顺便说一句,设置代码也一样.)

end

所以,这就是我们现在所处的位置:

def subdirs
  subdirs = []

  each { |entry|
    if File.directory?(File.join(path, entry))
      subdirs << entry
    end
  }

  return subdirs
end

正如您所看到的,if表达式实际上只用于跳过循环的一次迭代.使用next关键字可以更好地传达这一点:

def subdirs
  subdirs = []

  each { |entry|
    next  unless File.directory?(File.join(path, entry))
    subdirs << entry
  }

  return subdirs
end

如您所见,我们设法从块结构中删除了一级嵌套,这总是一个好兆头.

这个成语被称为"保护条款",在函数式编程中非常流行,其中许多语言甚至都内置了保护结构,但它在地球上几乎任何其他语言都被大量使用,因为它极大地简化了控制流程:这个想法类似于城堡外面的警卫:不是让坏人进入城堡(方法,程序,功能,阻挡......),然后痛苦地试图追踪他们的一举一动,不断地害怕错过一些东西或丢失它们,你只需在你的城堡入口(你的方法,块,......的开头)张贴一个警卫,他们不会让他们开始(跳到程序的最后) ,从方法返回,跳过循环的一次迭代,...).在Ruby中,你可以使用raise,return,nextbreak这一点.在其他语言中,即使GOTO是好的(这是极少数情况之一,GOTO实际上可以清除控制流程).

但是,通过识别迭代器模式,我们可以进一步简化这一过程:您获取一个列表(目录条目),然后将该列表"压缩"到一个对象(subdirs数组).对于一个类别理论家来说,这就是"catamorphism",一个硬核函数程序员" fold",一个软核函数程序员" reduce",一个Smalltalk程序员" inject:into:"和一个Rubyist" Enumerable#inject":

def subdirs
  return inject([]) { |subdirs, entry|
    next subdirs  unless File.directory?(File.join(path, entry))
    subdirs << entry
  }
end

inject使用前一次迭代的返回值来播种下一个迭代值,这就是为什么我们必须返回subdirs,即使我们正在跳过一个迭代,也可以使用next subdirs而不是plain next(它将返回nil,以便在下一次迭代时subdirs将会nil并且subdirs << entry会提高a NoMethodError.)

(注意我使用花括号作为块,即使块实际上修改了它的参数.我觉得这仍然是一个"功能"块.YMMV.)

我们能做的最后一件事就是要认识到我们正在做的只是过滤(或换句话说"选择")数组的元素.而Ruby已经内置了一个方法,它正是如此:Enumerable#select.见证使用Ruby的全部功能生成的单行精彩:

def subdirs
  return select { |entry| File.directory?(File.join(path, entry)) }
end

作为一般提示:学习奇迹Enumerable.它是Ruby编程主力,类似于IEnumerable.NET,dictPython中的函数式语言或PHP和Perl中的关联数组.

推荐阅读
农大军乐团_697
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有