A melhor maneira de exigir todos os arquivos de um diretório em ruby?


351

Qual é a melhor maneira de exigir todos os arquivos de um diretório em ruby?


Você pode criar um arquivo com o mesmo nome do diretório e solicitar todos os arquivos. O RSpec faz isso.
pedromanoel

Respostas:


462

E se:

Dir["/path/to/directory/*.rb"].each {|file| require file }

18
De acordo com o Pickaxe, a extensão .rb é opcional. Tecnicamente, ele muda o significado: "require 'foo.rb'" requer foo.rb, enquanto "require 'foo'" pode exigir foo.rb, foo.so ou foo.dll.
9339 Sam Stokes

28
Há uma pegadinha sutil para não retirar a extensão. Se alguma outra parte das chamadas de código exigir 'foo', o ruby ​​carregará o mesmo arquivo novamente, o que pode levar a erros espúrios. Eu adicionei minha própria resposta, que explica isso e mostra como remover a extensão.
Pete Hodgson

4
@Pete, isso ainda é verdade? Veja o comentário de Rene abaixo.
Andres Riofrio

5
Isso pode ser óbvio, mas vale a pena notar que a remoção do .rb também exigirá arquivos não-.rb no diretório, o que pode não ser o desejado.
user2398029

10
A sugestão de @ PeteHodgson é imprecisa. Ruby requirenão se confunde com a presença ou ausência da .rbextensão. Testado em ressonância magnética 1.8.7-p374, 2.1.5 e 2.2.0 testado. Essa lenda urbana vem do Rails, onde o carregamento automático "inteligente" exibia o comportamento que ele descreve em versões mais antigas (e ainda pode exibi-lo).
sheldonh

345

Se é um diretório relativo ao arquivo que requer (por exemplo, você deseja carregar todos os arquivos no diretório lib):

Dir[File.dirname(__FILE__) + '/lib/*.rb'].each {|file| require file }

Editar: com base nos comentários abaixo, uma versão atualizada:

Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }

14
Você também pode adicionar todos os diretórios filho como esteDir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
jspooner

62
Provavelmente é mais seguro usar File.join em vez de fazer suposições sobre barras frente / trás:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
Chris

6
Há também require_relative
maasha

30
Se você estiver usando> = ruby ​​2.0, poderá usar em __dir__vez de File.dirname(__FILE__).
Christian Bankester

3
@maasha Como você costuma require_relativeexigir todos os arquivos em um diretório?
David Moles

101

Experimente a gema require_all:

  1. http://github.com/jarmo/require_all
  2. https://rubygems.org/gems/require_all

Permite simplesmente:

require_all 'path/to/directory'

Eu precisava incluir todos os meus modelos do ActiveRecord, a gema require_all descobriu todas as dependências e as exigia perfeitamente. Obrigado!
panupan

2
@panupan Esteja ciente de que require_alla resolução de dependência cíclica soluciona um problema no seu código-fonte: você tem arquivos de origem Ruby que não requerem suas dependências. Isso fecha a porta no carregamento do bisturi, comprometendo-o a carregar tudo ou nada. Isso não é um problema em pequenas bibliotecas, mas é uma decisão que você deve tomar conscientemente.
sheldonh

Não faz sentido inchar seu aplicativo com gemas que você pode simplesmente substituir por uma linha de código. Isso aumenta o tempo de carregamento do seu aplicativo e induz mais erros a longo prazo.
Pere Joan Martorell

52
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

Se você não remover a extensão, poderá acabar solicitando o mesmo arquivo duas vezes (o ruby ​​não perceberá que "foo" e "foo.rb" são o mesmo arquivo). Exigir o mesmo arquivo duas vezes pode levar a avisos falsos (por exemplo, "aviso: constante já inicializada").


11
É este realmente o caso? A documentação diz: Um recurso não será carregado se o nome já aparecer em $ ". O nome do arquivo é convertido em um caminho absoluto; portanto," exige 'a'; require './a' "não carregará o a.rb duas vezes. ruby-doc.org/core/classes/Kernel.html#M001418
Derek

13
Meus testes mostram o mesmo que Derek disse: require "foo.rb"; require "foo";será carregado foo.rbapenas uma vez.
Rene Saarsoo

@ PeteHodgson- Você pode fazer backup disso?
Yarin

4
Não. Ruby requirenão se confunde com a presença ou ausência da .rbextensão. Testado na ressonância magnética 1.8.7-p374, 2.1.5 e 2.2.0. Essa lenda urbana vem do Rails, onde o carregamento automático "inteligente" exibia o comportamento descrito em versões mais antigas (e ainda pode exibi-lo).
sheldonh

45
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

ou, alternativamente, se você deseja definir o escopo dos arquivos para carregar em pastas específicas:

Dir.glob(File.join('path', '{folder1,folder2}', '**', '*.rb'), &method(:require))

explicação:

Dir.glob aceita um bloco como argumento.

O método (: require) retornará o método require.

& method (: require) converterá o método em um bloco.


2
Este é um código bonito. Eu amo como não há blocos visíveis.
Nate Symer #

11
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )elimina a dependência da plataforma (como '/' ou '\'). Funciona bem. Obrigado.
Ivan Black

30

A melhor maneira é adicionar o diretório ao caminho de carregamento e, em seguida, requireo nome da base de cada arquivo. Isso ocorre porque você deseja evitar exigir acidentalmente o mesmo arquivo duas vezes - geralmente não o comportamento pretendido. Se um arquivo será carregado ou não, depende se requireo caminho já foi passado antes. Por exemplo, esta sessão irb simples mostra que você pode exigir e carregar por engano o mesmo arquivo duas vezes.

$ irb
irb(main):001:0> require 'test'
=> true
irb(main):002:0> require './test'
=> true
irb(main):003:0> require './test.rb'
=> false
irb(main):004:0> require 'test'
=> false

Observe que as duas primeiras linhas retornam, o que truesignifica que o mesmo arquivo foi carregado nas duas vezes. Quando caminhos são usados, mesmo que apontem para o mesmo local, requirenão se sabe que o arquivo já foi necessário.

Aqui, em vez disso, adicionamos um diretório ao caminho de carregamento e, em seguida, exigimos o nome da base de cada arquivo * .rb.

dir = "/path/to/directory"
$LOAD_PATH.unshift(dir)
Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) }

Se você não se importa com o arquivo ser solicitado mais de uma vez, ou sua intenção é apenas carregar o conteúdo do arquivo, talvez loadseja melhor usá-lo em vez derequire . Use load neste caso, porque expressa melhor o que você está tentando realizar. Por exemplo:

Dir["/path/to/directory/*.rb"].each {|file| load file }

14

Em vez de concatenar caminhos, como em algumas respostas, eu uso File.expand_path:

Dir[File.expand_path('importers/*.rb', File.dirname(__FILE__))].each do |file|
  require file
end

Atualizar:

Em vez de usar, File.dirnamevocê pode fazer o seguinte:

Dir[File.expand_path('../importers/*.rb', __FILE__)].each do |file|
  require file
end

Onde ..retira o nome do arquivo __FILE__.


este parece definitivamente o caminho a percorrer, e mais até a resposta data, depois de tentar tudo o resto, +1 paraFile.expand_path
SuckerForMayhem

Definitivamente, prefiro essa resposta à aceita. Várias Rails.root.joinrespostas também funcionam se você estiver nos trilhos.
Nzifnab

14
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

Isso funcionará recursivamente na sua máquina local e em um controle remoto (como o Heroku) que não usa caminhos relativos.


8

No Rails, você pode fazer:

Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }

Atualização: corrigida com a sugestão de @Jiggneshh Gohel para remover barras.


Desde Rails.rooté um Pathnameexemplo, você pode fazer isso em qualquer ambiente Ruby, não apenas Trilhos (NB Rails.root.join('lib/ext/*.rb')lê um pouco mais agradável)
DMKE

Obrigado pela recomendação; Eu editei para incluir seu comentário.
Dan Kohn

Usar uma barra (/) para subdiretórios no Rails.root, por exemplo Rails.root.join('/lib'), não gera o caminho correto. Eu encontrei este para funcionar corretamente:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel 17/07/2015

@Jiggneshh Gohel Eu removi barras como você sugeriu, obrigado.
Dan Kohn

3

Estou alguns anos atrasado para a festa, mas eu meio que gosto dessa solução de uma linha que costumava usar trilhos para incluir tudo no aplicativo / trabalhadores / preocupações:

Dir[ Rails.root.join *%w(app workers concerns *) ].each{ |f| require f }


-2

E o que dizer require_relative *Dir['relative path']:?


11

OK, mas no meu exemplo não é. O '*' altera a aridade para 1. Ele funciona como uma chamada múltipla para require_relative.
Aleksander

11
O '*' altera a aridade para 1 - O que você quer dizer com isso? require_relative *Dir['*.rb']trabalho, se houver apenas um script ruby. Mas se vários scripts ruby ​​forem encontrados, você obtémrequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
knut
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.