Il modo migliore per richiedere tutti i file da una directory in ruby?


351

Qual è il modo migliore per richiedere tutti i file da una directory in ruby?


È possibile creare un file con lo stesso nome della directory e richiedere tutti i file. RSpec fa questo.
Pedromanoel,

Risposte:


462

Che ne dite di:

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

18
Secondo Pickaxe, l'estensione .rb è facoltativa. Tecnicamente cambia il significato: "richiedono 'foo.rb'" richiede foo.rb, mentre "richiedono 'foo'" potrebbe richiedere foo.rb, foo.so o foo.dll.
Sam Stokes,

28
C'è un trucco sottile per non togliere l'estensione. Se qualche altra parte delle chiamate in codice richiede 'pippo', ruby ​​caricherà di nuovo lo stesso file, il che può portare a errori spuri. Ho aggiunto la mia risposta che lo spiega e mostra come eliminare l'estensione.
Pete Hodgson,

4
@Pete, è ancora vero? Vedi il commento di René di seguito.
Andres Riofrio,

5
Questo potrebbe essere ovvio, ma vale la pena notare che l'eliminazione del file .rb richiederà anche qualsiasi file non .rb nella directory, il che potrebbe non essere desiderato.
user2398029

10
Il suggerimento di PeteHodgson è impreciso. Ruby requirenon è confuso dalla presenza o dall'assenza .rbdell'estensione. Testato su MRI 1.8.7-p374, 2.1.5 e 2.2.0 testato. Questa leggenda urbana proviene da Rails, dove il caricamento automatico "intelligente" ha mostrato il comportamento che descrive nelle versioni precedenti (e potrebbe ancora mostrarlo).
sheldonh,

345

Se è una directory relativa al file che soddisfa i requisiti (ad esempio, si desidera caricare tutti i file nella directory lib):

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

Modifica: in base ai commenti di seguito, una versione aggiornata:

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

14
Puoi anche aggiungere tutte le directory Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
secondarie

62
Probabilmente è più sicuro usare File.join piuttosto che fare ipotesi sulle barre in avanti / indietro:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
Chris

6
C'è anche
request_relative

30
Se stai usando> = ruby ​​2.0, puoi usare __dir__invece di File.dirname(__FILE__).
Christian Bankester,

3
@maasha Come si usa require_relativeper richiedere tutti i file in una directory?
David Moles,

101

Prova la gemma request_all:

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

Ti permette semplicemente:

require_all 'path/to/directory'

Avevo bisogno di includere tutti i miei modelli ActiveRecord, la gemma request_all ha capito tutte le dipendenze e le ha richieste perfettamente. Grazie!
Panupan,

2
@panupan Basta essere consapevoli del fatto che require_allla risoluzione ciclica delle dipendenze risolve un problema nel codice sorgente: ci sono file sorgente Ruby che non richiedono le loro dipendenze. Questo chiude la porta al caricamento del bisturi, impegnandoti a caricare tutto o niente. Questo non è un problema nelle piccole librerie, ma è una decisione che dovresti prendere consapevolmente.
sheldonh,

Non ha senso gonfiare la tua app con gemme che puoi semplicemente sostituire con una riga di codice. Ciò aumenta il tempo di caricamento della tua app e induce più bug a lungo termine.
Pere Joan Martorell,

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

Se non estrai l'estensione, potresti finire per richiedere lo stesso file due volte (ruby non capirà che "foo" e "foo.rb" sono lo stesso file). Richiedere lo stesso file due volte può comportare avvisi spuri (ad es. "Avviso: costante già inizializzata").


11
È davvero così? La documentazione dice: Una funzione non verrà caricata se il suo nome appare già in $ ". Il nome del file viene convertito in un percorso assoluto, quindi" richiede 'a'; richiedono './a' "non caricherà a.rb due volte. ruby-doc.org/core/classes/Kernel.html#M001418
Derek

13
I miei test mostrano lo stesso che Derek ha detto: require "foo.rb"; require "foo";caricherà foo.rbsolo una volta.
Rene Saarsoo,

@ PeteHodgson- Puoi supportarlo?
Yarin,

4
No. Ruby requirenon è confuso dalla presenza o dall'assenza .rbdell'estensione. Testato su MRI 1.8.7-p374, 2.1.5 e 2.2.0. Questa leggenda urbana proviene da Rails, dove il caricamento automatico "intelligente" mostrava il comportamento descritto nelle versioni precedenti (e può ancora mostrarlo).
sheldonh,

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

o in alternativa, se si desidera eseguire l'oscillazione dei file da caricare in cartelle specifiche:

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

spiegazione:

Dir.glob prende un blocco come argomento.

metodo (: requisito) restituirà il metodo richiesto.

& method (: request) convertirà il metodo in un blocco.


2
Questo è un bel codice. Adoro come non ci siano blocchi visibili.
Nate Symer,

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )elimina la dipendenza dalla piattaforma (come '/' o '\'). Funziona bene. Grazie.
Ivan Black

30

Il modo migliore è aggiungere la directory al percorso di caricamento e quindi requireil nome di base di ciascun file. Questo perché si desidera evitare di richiedere accidentalmente lo stesso file due volte, spesso non il comportamento previsto. Se un file verrà caricato o meno dipende dal fatto che requireabbia già visto il percorso passato ad esso. Ad esempio, questa semplice sessione IRB mostra che è possibile erroneamente richiedere e caricare due volte lo stesso file.

$ 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

Si noti che le prime due righe restituiscono il che truesignifica che lo stesso file è stato caricato entrambe le volte. Quando vengono utilizzati i percorsi, anche se i percorsi puntano nella stessa posizione,require non sanno che il file era già richiesto.

Qui invece, aggiungiamo una directory al percorso di caricamento e quindi richiediamo il nome di base di ciascun file * .rb all'interno.

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

Se non ti interessa il file richiesto più di una volta, o la tua intenzione è solo quella di caricare il contenuto del file, forse loaddovrebbe essere usato al posto di require. Usa load in questo caso, perché esprime meglio ciò che stai cercando di realizzare. Per esempio:

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

14

Invece di concatenare percorsi come in alcune risposte, utilizzo File.expand_path:

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

Aggiornare:

Invece di usare File.dirnamepotresti fare quanto segue:

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

Dove ..rimuove il nome file di __FILE__.


questa sembra decisamente la strada da percorrere, e la risposta più aggiornata, dopo aver provato tutto il resto, +1 perFile.expand_path
SuckerForMayhem

Preferisco decisamente questa risposta a quella accettata. Diverse Rails.root.joinrisposte funzionano anche se sei su binari.
nzifnab,

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

Questo funzionerà in modo ricorsivo sul tuo computer locale e su un telecomando (come Heroku) che non utilizza percorsi relativi.


8

In Rails puoi fare:

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

Aggiornamento: corretto con il suggerimento di @Jiggneshh Gohel per rimuovere le barre.


Dato che Rails.rootè Pathnameun'istanza, puoi farlo in qualsiasi ambiente Ruby, non solo Rails (NB Rails.root.join('lib/ext/*.rb')legge un po 'meglio)
DMKE

Grazie per la raccomandazione; Ho modificato per includere il tuo commento.
Dan Kohn,

L'uso di una barra (/) per le sottodirectory di Rails.root, ad esempio Rails.root.join('/lib'), non genera il percorso corretto. Ho trovato questo per funzionare correttamente:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel,

@Jiggneshh Gohel Ho rimosso le barre come hai suggerito, grazie.
Dan Kohn,

3

Sono in ritardo di qualche anno alla festa, ma in un certo senso mi piace questa soluzione a una linea che ho usato per ottenere le rotaie per includere tutto in app / lavoratori / preoccupazioni:

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


-2

E che dire di require_relative *Dir['relative path']:?


1
Il parente richiesto non accetta
fabriciofreitag

OK, ma nel mio esempio non lo è. '*' Cambia arity in 1. Funziona come una chiamata multipla a request_relative.
Aleksander,

1
Il '*' cambia arity in 1 - Cosa intendi con esso? require_relative *Dir['*.rb']funziona, se c'è solo un copione rubino. Ma se vengono trovati più script ruby, ottienirequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
knut
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.