Избегайте нескольких вызовов Find.find ("./") в Ruby - PullRequest
1 голос
/ 01 октября 2010

Я не уверен, какова лучшая стратегия для этого. У меня есть класс, где я могу искать файловую систему по определенному шаблону файлов. Я хочу выполнить Find.find ("./") только один раз. как бы я подойти к этому:

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

Ответы [ 3 ]

4 голосов
/ 01 октября 2010

Запоминание (обычно интенсивного в вычислительном отношении) результата вызова метода, так что вам не нужно пересчитывать его при следующем вызове метода, называется памятка , так что вы будете вероятно, хотите узнать больше об этом.

Один из способов добиться этого в Ruby - использовать небольшой класс-обертку, который сохраняет результат в переменной экземпляра. например,

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

И тогда вы можете сделать:

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"]

Примечание: оператор ||= выполняет присваивание только в том случае, если переменная в левой части имеет значение false. то есть @matches ||= find_matches является сокращением для @matches = @matches || find_matches, где find_matches будет вызываться только в первый раз из-за оценки короткого замыкания. Существует множество других вопросов , объясняющих это в Stackoverflow.


Небольшое отклонение: вы можете изменить свой метод так, чтобы он возвращал список всех файлов , а затем использовать методы из Enumerable, такие как grep и select, для выполнения нескольких поисков по одному и тому же списку. файлы. Конечно, у этого есть недостаток - хранить весь список файлов в памяти. Вот пример, хотя:

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

А затем используйте его как:

files = find_all
files.grep /\.xml/
files.select { |f| f.include? '.cpp' }
# etc
1 голос
/ 01 октября 2010

Если я правильно понимаю ваш вопрос, вы хотите запустить Find.find, чтобы присвоить результат переменной экземпляра.Вы можете переместить то, что сейчас является блоком, в отдельный метод и вызвать его, чтобы получить только файлы, соответствующие вашему шаблону.

Единственная проблема заключается в том, что если в каталоге содержится много файлов, вы держите в памяти большой массив.

0 голосов
/ 01 октября 2010

как насчет system "find / -name #{my_pattern}"

...