Pergunta

Não tenho certeza de qual é a melhor estratégia para isso. Eu tenho uma classe, onde posso pesquisar no sistema de arquivos um determinado padrão de arquivos. Eu quero executar o find.find ("./") apenas uma vez. Como eu abordaria isso:

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

Solução

Lembrando o resultado (geralmente computacionalmente intensivo) de uma chamada de método para que você não precise recalculá -lo na próxima vez que o método for chamado é conhecido como memórias Então você provavelmente vai querer ler mais sobre isso.

Uma maneira de alcançar que Ruby é usar uma pequena classe de wrapper que armazena o resultado em uma variável de instância. por exemplo

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

E então você pode fazer:

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

Note o ||= O operador executa uma atribuição somente se a variável no lado esquerdo avaliará como false. ou seja @matches ||= find_matches é abreviado para @matches = @matches || find_matches Onde find_matches só será chamado na primeira vez devido à avaliação de curto -circuito. Há muitos outras perguntas explicando -o no StackOverflow.


Pequena variação: você pode alterar seu método para retornar uma lista de todos os arquivos e depois use métodos de Enumerable tal como grep e select Para executar várias pesquisas em relação à mesma lista de arquivos. Obviamente, isso tem a desvantagem de manter toda a lista de arquivos na memória. Aqui está um exemplo:

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

E então use -o como:

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

Outras dicas

Se eu entendi sua pergunta corretamente, você deseja executar o Find.dinding para atribuir o resultado a uma variável de instância. Você pode mover o que agora é o bloco para um método separado e chamar isso para retornar apenas arquivos que correspondem ao seu padrão.

O único problema é que, se o diretório contiver muitos arquivos, você estará segurando uma grande matriz na memória.

e quanto a system "find / -name #{my_pattern}"

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top