Evitando fazer várias chamadas para encontrar.Find ("./") em Ruby
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
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}"