ruby on rails -递归方法不返回到调用者的前一行位置



我一直在试图找到一个解决这个问题的一段时间。我已经找到了关于递归的问题和答案,但似乎没有一个适合这种特殊情况。

我写了一个类,应该通过给定的文件夹和所有子文件夹和重命名文件和文件夹,如果一个特定的搜索模式被发现。

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

我知道解决实际用例的其他方法,但我无法解释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

你有一个bug。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. 你应该在库中包含这样一个部分,允许从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中调用它,然后将当前目录更改为test,在目录中,getValidDirEntries('test')将无法正常工作。
  3. 您应该只使用正斜杠而不是双倒斜杠。所以你的代码也可以在Linux和Mac OS X上运行。
  4. 当您实例化MultiFileAndFolderRename的新实例时(这是不必要的),初始化器的参数是错误的。相反,你应该使用你当前的实例,只调用self.replaceAllInDir(newDir)而不是rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString');rntemp.replaceAllInDir(newDir)

我认为错误的实例化是它不像预期的那样工作的主要原因,但其他的也应该修复。

最新更新