Frage

Ich bin mir nicht sicher, was dafür die beste Strategie ist. Ich habe eine Klasse, in der ich das Dateisystem nach einem bestimmten Dateienmuster durchsuchen kann. Ich möchte Find.find ("./") nur einmal ausführen. Wie würde ich mich dem nähern:

  def files_pattern(pattern)
    Find.find("./") do |f| 
      if f.include? pattern
           @fs << f
      end
    end
  end
War es hilfreich?

Lösung

Erinnern Sie sich an das (normalerweise rechenintensive) Ergebnis eines Methodenaufrufs, damit Sie ihn nicht neu berechnen müssen, wenn die Methode aufgerufen wird Memoisierung Sie werden also wahrscheinlich mehr darüber lesen möchten.

Eine Möglichkeit zu erreichen, dass Ruby eine kleine Wrapper -Klasse verwenden kann, die das Ergebnis in einer Instanzvariablen speichert. z.B

class Finder
  def initialize(pattern)
    @pattern = pattern
  end

  def matches
    @matches ||= find_matches
  end

  private

  def find_matches
    fs = []
    Find.find("./") do |f| 
      if f.include? @pattern
        fs << f
      end
    end
    fs
  end
end

Und dann können Sie:

irb(main):089:0> f = Finder.new 'xml'
=> #<Finder:0x2cfc568 @pattern="xml">
irb(main):090:0> f.matches
find_matches
=> ["./example.xml"]
irb(main):091:0> f.matches # won't result in call to find_matches
=> ["./example.xml"]

Beachten Sie das ||= Der Bediener führt eine Zuordnung nur aus, wenn die Variable auf der linken Seite auf False bewertet wird. dh @matches ||= find_matches ist Kurzschrift für @matches = @matches || find_matches wo find_matches wird nur aufgrund der Kurzschlussbewertung als erstes bezeichnet. Da sind viele andere Fragen Erklären Sie es auf Stackoverflow.


Leichte Variation: Sie können Ihre Methode ändern, um eine Liste von zurückzugeben alle Dateien und dann Methoden von verwenden Enumerable wie zum Beispiel grep und select Um mehrere Suchvorgänge mit derselben Liste von Dateien durchzuführen. Dies hat natürlich den Nachteil, die gesamte Liste der Dateien im Speicher zu halten. Hier ist jedoch ein Beispiel:

def find_all
  fs = []
  Find.find("./") do |f| 
    fs << f
  end
  fs
end

Und dann benutze es wie:

files = find_all
files.grep /\.xml/
files.select { |f| f.include? '.cpp' }
# etc

Andere Tipps

Wenn ich Ihre Frage richtig verstehe, möchten Sie Find.find ausführen, um das Ergebnis einer Instanzvariablen zuzuweisen. Sie können den Block auf eine separate Methode verschieben und diese aufrufen, um nur Dateien zurückzugeben, die Ihrem Muster entsprechen.

Das einzige Problem ist, dass Sie, wenn das Verzeichnis viele Dateien enthält, ein großes Array im Speicher halten.

wie wäre es mit system "find / -name #{my_pattern}"

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top