Der beste Weg, um alle Dateien aus einem Verzeichnis in Ruby zu benötigen?


351

Was ist der beste Weg, um alle Dateien aus einem Verzeichnis in Ruby zu benötigen?


Sie können eine Datei mit demselben Namen wie das Verzeichnis erstellen, für die alle Dateien erforderlich sind. RSpec macht das.
Pedromanoel

Antworten:


462

Wie wäre es mit:

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

18
Laut Pickaxe ist die Erweiterung .rb optional. Technisch ändert sich die Bedeutung: "require 'foo.rb'" erfordert foo.rb, während "require 'foo'" möglicherweise foo.rb, foo.so oder foo.dll erfordert.
Sam Stokes

28
Es ist ein subtiles Problem, die Erweiterung nicht zu entfernen. Wenn für einen anderen Teil der Codeaufrufe 'foo' erforderlich ist, lädt Ruby dieselbe Datei erneut, was zu falschen Fehlern führen kann. Ich habe meine eigene Antwort hinzugefügt, die das erklärt und zeigt, wie die Erweiterung entfernt wird.
Pete Hodgson

4
@Pete, ist das noch wahr? Siehe Renes Kommentar unten.
Andres Riofrio

5
Dies mag offensichtlich sein, aber es ist erwähnenswert, dass zum Löschen der .rb-Datei auch alle Nicht-.rb-Dateien im Verzeichnis erforderlich sind, was möglicherweise nicht erwünscht ist.
user2398029

10
@ PeteHodgsons Vorschlag ist ungenau. Ruby requireist nicht durch das Vorhandensein oder Fehlen der .rbErweiterung verwirrt . Getestet auf MRT 1.8.7-p374, 2.1.5 und 2.2.0 getestet. Diese urbane Legende stammt von Rails, wo "cleveres" Autoloading das Verhalten zeigte, das er in älteren Versionen beschreibt (und möglicherweise noch zeigt).
Sheldonh

345

Wenn es sich um ein Verzeichnis handelt, das sich auf die Datei bezieht, die die Anforderungen erfüllt (z. B. möchten Sie alle Dateien in das lib-Verzeichnis laden):

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

Bearbeiten: Basierend auf den Kommentaren unten, eine aktualisierte Version:

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

14
Sie können auch alle Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
untergeordneten

62
Es ist wahrscheinlich sicherer, File.join zu verwenden, als Annahmen über Schrägstriche vorwärts / rückwärts zu treffen:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
Chris

6
Es gibt auch require_relative
maasha

30
Wenn Sie> = Ruby 2.0 verwenden, können Sie __dir__anstelle von verwenden File.dirname(__FILE__).
Christian Bankester

3
@maasha Wie verwenden Sie require_relative, um alle Dateien in einem Verzeichnis zu benötigen?
David Moles

101

Probieren Sie das Juwel require_all aus:

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

Sie können einfach:

require_all 'path/to/directory'

Ich musste alle meine ActiveRecord-Modelle einbeziehen, das Juwel require_all hat alle Abhängigkeiten herausgefunden und sie perfekt benötigt. Vielen Dank!
Panupan

2
@panupan Beachten Sie jedoch, dass require_alldie zyklische Abhängigkeitsauflösung ein Problem in Ihrem Quellcode umgeht : Sie haben Ruby-Quelldateien, für die keine Abhängigkeiten erforderlich sind. Dies schließt die Tür beim Laden des Skalpells und verpflichtet Sie zum Alles-oder-Nichts-Laden. In kleinen Bibliotheken ist das kein Problem, aber es ist eine Entscheidung, die Sie bewusst treffen sollten.
Sheldonh

Es macht keinen Sinn, Ihre App mit Edelsteinen aufzublähen, die Sie einfach durch eine Codezeile ersetzen können. Dies erhöht die Ladezeit Ihrer App und führt langfristig zu mehr Fehlern.
Pere Joan Martorell

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

Wenn Sie die Erweiterung nicht entfernen, benötigen Sie möglicherweise zweimal dieselbe Datei (Ruby merkt nicht, dass "foo" und "foo.rb" dieselbe Datei sind). Das zweimalige Anfordern derselben Datei kann zu falschen Warnungen führen (z. B. "Warnung: bereits initialisierte Konstante").


11
Ist das wirklich der Fall? In der Dokumentation heißt es: Ein Feature wird nicht geladen, wenn sein Name bereits in $ "erscheint. Der Dateiname wird in einen absoluten Pfad konvertiert, daher" erfordert 'a'; require './a' "lädt a.rb nicht zweimal. ruby-doc.org/core/classes/Kernel.html#M001418
Derek

13
Meine Tests zeigen dasselbe, was Derek gesagt hat: require "foo.rb"; require "foo";Wird foo.rbnur einmal geladen .
Rene Saarsoo

@ PeteHodgson- Kannst du das sichern?
Yarin

4
Ruby's requireist nicht durch das Vorhandensein oder Fehlen der .rbErweiterung verwirrt . Getestet auf MRT 1.8.7-p374, 2.1.5 und 2.2.0. Diese urbane Legende stammt von Rails, wo "cleveres" Autoloading das in älteren Versionen beschriebene Verhalten zeigte (und es möglicherweise noch zeigt).
Sheldonh

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

oder alternativ, wenn Sie die Dateien in bestimmte Ordner laden möchten:

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

Erläuterung:

Dir.glob nimmt einen Block als Argument.

Methode (: erfordern) gibt die require-Methode zurück.

& method (: require) konvertiert die Methode in einen Block.


2
Dies ist ein wunderschöner Code. Ich liebe es, wie es keine sichtbaren Blöcke gibt.
Nate Symer

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )beseitigt die Abhängigkeit von der Plattform (wie '/' oder '\'). Funktioniert gut. Vielen Dank.
Ivan Black

30

Der beste Weg ist, das Verzeichnis zum requireLadepfad und dann den Basisnamen jeder Datei hinzuzufügen . Dies liegt daran, dass Sie vermeiden möchten, dass dieselbe Datei versehentlich zweimal benötigt wird - häufig nicht das beabsichtigte Verhalten. Ob eine Datei geladen wird oder nicht, hängt davon ab, ob requireder Pfad zuvor an sie übergeben wurde. Diese einfache irb-Sitzung zeigt beispielsweise, dass Sie fälschlicherweise dieselbe Datei zweimal benötigen und laden können.

$ 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

Beachten Sie, dass die ersten beiden Zeilen zurückgegeben werden, truewas bedeutet, dass dieselbe Datei beide Male geladen wurde. Wenn Pfade verwendet werden, auch wenn die Pfade auf denselben Ort verweisen,require ist nicht bekannt, dass die Datei bereits erforderlich war.

Hier fügen wir stattdessen dem Ladepfad ein Verzeichnis hinzu und benötigen dann den Basisnamen jeder darin enthaltenen * .rb-Datei.

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

Wenn Sie sich nicht darum kümmern, dass die Datei mehr als einmal benötigt wird, oder wenn Sie nur den Inhalt der Datei laden möchten, loadsollten Sie sie möglicherweise anstelle von verwenden require. Verwenden Sie in diesem Fall load, da es besser ausdrückt, was Sie erreichen möchten. Zum Beispiel:

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

14

Anstatt Pfade wie in einigen Antworten zu verketten, verwende ich File.expand_path:

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

Aktualisieren:

Anstatt zu verwenden, können File.dirnameSie Folgendes tun:

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

Wobei ..der Dateiname entfernt wird __FILE__.


Dies scheint definitiv der File.expand_path
richtige

Ich ziehe diese Antwort definitiv der akzeptierten vor. Verschiedene Rails.root.joinAntworten funktionieren auch, wenn Sie in Schienen sind.
Nzifnab

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

Dies funktioniert rekursiv auf Ihrem lokalen Computer und einer Fernbedienung (wie Heroku), die keine relativen Pfade verwendet.


8

In Rails können Sie Folgendes tun:

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

Update: Korrigiert mit dem Vorschlag von @Jiggneshh Gohel, Schrägstriche zu entfernen.


Da Rails.rootes sich um eine PathnameInstanz handelt, können Sie dies in jeder Ruby-Umgebung tun, nicht nur in Rails (NB Rails.root.join('lib/ext/*.rb')liest sich etwas
besser

Danke für die Empfehlung; Ich habe bearbeitet, um Ihren Kommentar aufzunehmen.
Dan Kohn

Die Verwendung eines Schrägstrichs (/) für Unterverzeichnisse unter Rails.root Rails.root.join('/lib')generiert beispielsweise keinen korrekten Pfad. Ich fand, dass dieses richtig funktioniert:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel

@ Jiggneshh Gohel Ich habe Schrägstriche entfernt, wie Sie vorgeschlagen haben, danke.
Dan Kohn

3

Ich bin ein paar Jahre zu spät zur Party, aber ich mag diese einzeilige Lösung, mit der ich Schienen dazu gebracht habe, alles in App / Worker / Anliegen aufzunehmen:

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


-2

Und was ist mit : require_relative *Dir['relative path']?



OK, aber in meinem Beispiel ist es nicht. Das '*' ändert die Arität in 1. Es funktioniert als Mehrfachaufruf von require_relative.
Aleksander

1
Das '*' ändert die Arität in 1 - Was meinst du damit? require_relative *Dir['*.rb']Arbeit, wenn es nur ein Ruby-Skript gibt. Aber wenn mehrere Ruby-Skripte gefunden werden, erhalten Sierequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
knut
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.