递归方法不返回调用者中的上一行位置

时间:2011-07-10 12:33:52

标签: ruby-on-rails ruby

我一直试图找到解决方案。我已经找到了关于递归的问题和答案,但似乎没有任何东西适合这种特殊情况。

如果找到特定的搜索模式,我编写了一个应该遍历给定文件夹和所有子文件夹并重命名文件和文件夹的类。

一切按预期工作,可以调用replaceAllInDir,如果需要,它会替换文件和文件夹。然后,下一步是对给定文件夹中的所有子文件夹执行相同操作。 因此,可以识别子文件夹,并从内部调用replaceAllInDir。让我们假设所调用的特定子文件夹不包含任何子文件夹。我希望我们返回到父文件夹并继续查找其他子文件夹。但是控制不会返回到父调用方法,程序结束。

我知道解决实际用例的其他方法,但我无法解释ruby的行为。

class MultiFileAndFolderRename
  attr_accessor :rootDir, :searchPattern, :replacePattern

  def initialize(rootDir, searchPattern, replacePattern)
    @rootDir = rootDir
    @searchPattern = searchPattern
    @replacePattern = replacePattern
  end

  def execute
    replaceAllInDir(@rootDir)
  end

  def getValidDirEntries(dir)
    dirList = Dir.entries(dir)
    dirList.delete('.')
    dirList.delete('..')
    dirList
  end

  def replaceAllInDir(currentDir)
    Dir.chdir(currentDir)
    puts "Processing directory: " + Dir.pwd
    dirList = getValidDirEntries(currentDir)
    dirList.each { |dirEntry|
      attemptRename(dirEntry)
    }

    dirList = getValidDirEntries(currentDir)
    dirList.each { |dirEntry|
      if File.directory?(dirEntry)
        newDir = currentDir + '\\' + dirEntry
        rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString')
        rntemp.replaceAllInDir(newDir)
      end
    }
  end

  def attemptRename(dirEntry)
    if dirEntry.match(@searchPattern)
      newname = dirEntry.to_s.sub(@searchPattern, @replacePattern)
      FileUtils.mv(dirEntry.to_s, newname)
    end
  end
end

2 个答案:

答案 0 :(得分:2)

你有一个错误。 replaceAllInDir()的第一行是Dir.chdir()chdir()在全局范围内更改当前进程的目录。它不依赖于调用堆栈。因此,当您进入子目录并更改为该子目录时,即使您从递归返回,更改也将成为永久更改。

在调用replaceAllInDir()后,您需要更改回正确的目录。例如:

...
dirList.each { |dirEntry|
  if File.directory?(dirEntry)
    ....
    rntemp.replaceAllInDir(newDir)
    Dir.chdir(currentDir) # <- Restore us back to the correct directory
  end
}

答案 1 :(得分:1)

我已经尝试过你的代码了,我发现了很多错误。也许如果你修复它们,你的想法就可以了。

  1. 你应该在类似的库中包含一个允许从shell调用它的部分:MultiFileAndFolderRename.new(ARGV[0], ARGV[1], ARGV[2]).execute if __FILE__ == $0这可以确保当你通过ruby rename.rb test old new从shell调用ruby代码时,你的类将被实例化,并将相应地设置搜索和替换模式。
  2. 您不应该设置当前目录,因为这可以确保行getValidDirEntries(currentDir)不起作用。如果你,例如。将其命名为目录测试,然后将当前目录更改为test,在目录中,getValidDirEntries('test')将无法正常工作。
  3. 您应该只使用正斜杠而不是双向反斜杠。因此,您的代码也适用于Linux和Mac OS X.
  4. 当您实例化MultiFileAndFolderRename的新实例(这是不必要的)时,初始化程序的参数是错误的。相反,您应该使用当前实例,只需拨打self.replaceAllInDir(newDir)而不是rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString');rntemp.replaceAllInDir(newDir)
  5. 我认为错误的实例化是它不能按预期工作的主要原因,但其他的也应该修复。