2011-07-10 4 views
1

私はしばらくの間、これに対する解決策を見つけようとしてきました。私は再帰に関する質問と回答を見つけましたが、この特定の状況に合うようなものは何も見つかりませんでした。再帰メソッドが呼び出し元の前の行の位置に戻っていない

特定の検索パターンが見つかった場合は、指定されたフォルダとすべてのサブフォルダとファイルとフォルダの名前を変更するクラスを作成しました。

すべてが正常に動作し、replaceAllInDirが呼び出されると、必要に応じてファイルとフォルダが置き換えられます。次のステップは、指定されたフォルダ内のすべてのサブフォルダに対して同じ操作を実行することです。 したがって、サブフォルダは特定され、replaceAllInDirはその内部から呼び出されます。呼び出される特定のサブフォルダにサブフォルダが含まれていないと仮定します。私は親フォルダに戻り、他のサブフォルダを探し続けることを期待します。しかし、代わりにコントロールは親の呼び​​出しメソッドに返されず、プログラムは終了します。

私は実際のユースケースを解決する他の方法を知っていますが、私はルビーの動作を説明することはできません。

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 
+0

あなたのロジックは大丈夫です(あなたのルビーコーディング規則は普通よりも小さいですが))。あなたは理論的に再帰的にすべきディレクトリへのパスを出力しようとしましたか?これは、名前変更されたディレクトリの名前が何らかのキャッシュのために見えている可能性があります。したがって、 'File.directory?'は、 'dirlist'を2回目に反復するときにtrueを返しません。 – d11wtq

答えて

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 
} 
+0

これが問題でした。どうもありがとうございました! – Jan

1

私はあなたのコードを試しましたが、その中に数多くのエラーが見つかりました。もしあなたがそれらを修正すれば、あなたの考えは働いているでしょう。

  1. あなたはシェルからそれを呼び出すことができます最後の部分というようにライブラリに含まれている必要がありますMultiFileAndFolderRename.new(ARGV[0], ARGV[1], ARGV[2]).execute if __FILE__ == $0これはあなたがruby rename.rb test old newによってシェルからRubyのコードを呼び出すときに、あなたのクラスをインスタンス化することが保証されますと、それに応じて検索と置換のパターンが設定されます。
  2. 現在のディレクトリを設定しないでください。これは、getValidDirEntries(currentDir)という行が確実に機能しないためです。もしあなた。ディレクトリテストのために呼び出すと、ディレクトリ内の現在のディレクトリをテストするように変更すると、getValidDirEntries('test')は期待どおりに動作しません。
  3. 逆方向のものの代わりにスラッシュのみを使用してください。したがって、あなたのコードは、LinuxとMac OS Xでも動作します。
  4. 新しいインスタンスMultiFileAndFolderRename(これは必須ではありません)をインスタンス化すると、イニシャライザの引数が間違っています。代わりに、現在のインスタンスを使用し、rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString');rntemp.replaceAllInDir(newDir)の代わりにself.replaceAllInDir(newDir)を呼び出すだけです。

私は間違ったインスタンス化が、期待通りに動作しない主な理由だと思いますが、他のものも同様に修正する必要があります。

+0

私はすべてのコメントを取ってきました。そして、問題の修正がそこにあったのは間違いありません。これに答える際の詳細と時間をありがとうございました。 – Jan

+0

どうか私にそれについての親指を与えてください:-) – mliebelt

関連する問題