Najlepszy sposób, aby wymagać wszystkich plików z katalogu w Rubim?

351

Jaki jest najlepszy sposób, aby wymagać wszystkich plików z katalogu w Rubim?

Gaetan Dubar
źródło
Możesz utworzyć plik o tej samej nazwie katalogu i wymagać, aby wszystkie pliki. RSpec to robi.
pedromanoel

Odpowiedzi:

462

Co powiesz na:

Dir["/path/to/directory/*.rb"].each {|file| require file }
Sam Stokes
źródło
18
Według Pickaxe rozszerzenie .rb jest opcjonalne. Technicznie zmienia to znaczenie: „wymaga„ foo.rb ”” wymaga foo.rb, natomiast „wymaga„ foo ”” może wymagać foo.rb, foo.so lub foo.dll.
Sam Stokes,
28
Subtelne jest, aby nie zdejmować rozszerzenia. Jeśli jakaś inna część wywołań kodu wymaga „foo”, Ruby ponownie załaduje ten sam plik, co może prowadzić do fałszywych błędów. Dodałem własną odpowiedź, która to wyjaśnia i pokazuje, jak usunąć rozszerzenie.
Pete Hodgson,
4
@Pete, czy to nadal prawda? Zobacz komentarz Rene poniżej.
Andres Riofrio,
5
Może to być oczywiste, ale warto zauważyć, że upuszczenie pliku .rb będzie wymagało również plików innych niż .rb w katalogu, co może nie być pożądane.
user2398029,
10
@ Sugestia PeteHodgsona jest niedokładna. Ruby's requirenie jest zdezorientowana obecnością lub brakiem .rbrozszerzenia. Testowany na MRI 1.8.7-p374, 2.1.5 i 2.2.0. Ta miejska legenda pochodzi z Railsów, gdzie „sprytne” automatyczne ładowanie pokazało zachowanie, które opisuje w starszych wersjach (i nadal może to wykazywać).
sheldonh
345

Jeśli jest to katalog względem pliku, który spełnia wymagania (np. Chcesz załadować wszystkie pliki do katalogu lib):

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

Edycja: na podstawie poniższych komentarzy zaktualizowana wersja:

Dir[File.join(__dir__, 'lib', '*.rb')].each { |file| require file }
jandot
źródło
14
Możesz także dodać wszystkie katalogi potomne w ten sposóbDir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
jspooner
62
Prawdopodobnie bezpieczniej jest korzystać z File.join niż przyjmować założenia dotyczące ukośników do przodu / do tyłu:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
Chris
6
Jest też
wymagany_relatyw
30
Jeśli używasz> = ruby ​​2.0, możesz użyć __dir__zamiast File.dirname(__FILE__).
Christian Bankester
3
@maasha W jaki sposób require_relativepotrzebujesz wszystkich plików w katalogu?
David Moles,
101

Wypróbuj klejnot requ_all:

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

Pozwala po prostu:

require_all 'path/to/directory'

źródło
Musiałem dołączyć wszystkie moje modele ActiveRecord, klejnot wymagający wszystkich rozpoznał wszystkie zależności i wymagał ich idealnie. Dzięki!
panupan
2
@panupan Pamiętaj, że require_allcykliczne rozwiązywanie zależności rozwiązuje problem w kodzie źródłowym: masz pliki źródłowe Ruby, które nie wymagają ich zależności. To zamyka drzwi przy ładowaniu skalpela, zobowiązując cię do załadowania wszystkiego albo nic. W małych bibliotekach nie stanowi to problemu, ale decyzję należy podjąć świadomie.
sheldonh
Nie ma sensu przesadzać aplikacji klejnotami, które można po prostu zastąpić wierszem kodu. Zwiększa to czas ładowania aplikacji i powoduje więcej błędów w dłuższej perspektywie.
Pere Joan Martorell
52
Dir[File.dirname(__FILE__) + '/../lib/*.rb'].each do |file| 
  require File.basename(file, File.extname(file))
end

Jeśli nie usuniesz rozszerzenia, możesz potrzebować dwa razy tego samego pliku (Ruby nie zdaje sobie sprawy, że „foo” i „foo.rb” są tym samym plikiem). Wymaganie dwa razy tego samego pliku może prowadzić do fałszywych ostrzeżeń (np. „Ostrzeżenie: już zainicjowana stała”).

Pete Hodgson
źródło
11
Czy to naprawdę tak jest? Dokumentacja mówi: Funkcja nie zostanie załadowana, jeśli jej nazwa pojawia się już w $ ". Nazwa pliku jest konwertowana na ścieżkę bezwzględną, więc" wymaga "a"; wymagają „./a” ”nie ładuje dwukrotnie pliku a.rb. ruby-doc.org/core/classes/Kernel.html#M001418
Derek
13
Moje testy pokazują to samo, co powiedział Derek: require "foo.rb"; require "foo";ładuje się foo.rbtylko raz.
Rene Saarsoo,
@ PeteHodgson- Czy możesz to zrobić?
Yarin
4
Nie. Ruby's requirenie jest zdezorientowana obecnością lub brakiem .rbrozszerzenia. Testowany na MRI 1.8.7-p374, 2.1.5 i 2.2.0. Ta miejska legenda pochodzi z Railsów, gdzie „sprytne” automatyczne ładowanie pokazało zachowanie opisane w starszych wersjach (i może nadal je wykazywać).
sheldonh
45
Dir.glob(File.join('path', '**', '*.rb'), &method(:require))

lub alternatywnie, jeśli chcesz zawęzić zakres plików do załadowania do określonych folderów:

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

wyjaśnienie:

Dir.glob przyjmuje blok jako argument.

Metoda (: wymaga) zwróci metodę wymaganą.

& method (: wymagany) przekształci metodę w blok.

metakungfu
źródło
2
To jest piękny kod. Uwielbiam to, że nie ma widocznych bloków.
Nate Symer
1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )eliminuje zależność od platformy (np. „/” lub „\”). Działa dobrze. Dzięki.
Ivan Black
30

Najlepszym sposobem jest dodanie katalogu do ścieżki ładowania, a następnie requirenazwy bazowej każdego pliku. Wynika to z faktu, że chcesz uniknąć przypadkowego wymagania dwukrotnie tego samego pliku - często nie zamierzonego zachowania. To, czy plik zostanie załadowany, zależy od tego, czy requirewcześniej widziała ścieżkę do niego przesłaną. Na przykład ta prosta sesja IRB pokazuje, że można przez pomyłkę zażądać i załadować ten sam plik dwukrotnie.

$ 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

Zauważ, że pierwsze dwa wiersze zwracają, trueco oznacza, że ​​ten sam plik został załadowany dwa razy. Gdy ścieżki są używane, nawet jeśli ścieżki wskazują tę samą lokalizację, requirenie wie, że plik był już wymagany.

Zamiast tego dodajemy katalog do ścieżki ładowania, a następnie wymagamy nazwy basenowej każdego pliku * .rb.

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

Jeśli nie zależy ci na tym, że plik jest wymagany więcej niż jeden raz, lub chcesz po prostu załadować zawartość pliku, być może loadpowinno się go użyć require. W tym przypadku użyj obciążenia, ponieważ lepiej wyraża to, co próbujesz osiągnąć. Na przykład:

Dir["/path/to/directory/*.rb"].each {|file| load file }
Ryan McGeary
źródło
14

Zamiast łączyć ścieżki jak w niektórych odpowiedziach, używam File.expand_path:

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

Aktualizacja:

Zamiast używać File.dirnamemożesz wykonać następujące czynności:

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

Gdzie ..usuwa nazwę pliku __FILE__.

Koen
źródło
wydaje się to zdecydowanie właściwą drogą, a najbardziej aktualna odpowiedź, po wypróbowaniu całej reszty, +1 zaFile.expand_path
SuckerForMayhem
Zdecydowanie wolę tę odpowiedź od zaakceptowanej. Różne Rails.root.joinodpowiedzi działają również, jeśli jesteś w szynach.
nzifnab
14
Dir[File.join(__dir__, "/app/**/*.rb")].each do |file|
  require file
end

Będzie to działało rekurencyjnie na twoim komputerze lokalnym i zdalnym (takim jak Heroku), który nie używa ścieżek względnych.

shushugah
źródło
8

W Railsach możesz:

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

Aktualizacja: Poprawione z sugestią @Jiggneshh Gohel, aby usunąć ukośniki.

Dan Kohn
źródło
Ponieważ Rails.rootjest to Pathnameprzykład, możesz to zrobić w dowolnym środowisku Ruby, nie tylko w Railsach (NB Rails.root.join('lib/ext/*.rb')jest trochę ładniejszy)
DMKE
Dzięki za rekomendację; Zredagowałem, aby dodać Twój komentarz.
Dan Kohn
Użycie ukośnika (/) dla podkatalogów w Rails.root, np. Rails.root.join('/lib')Nie generuje poprawnej ścieżki. Odkryłem, że działa poprawnie:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel
@Jiggneshh Gohel Usunąłem ukośniki, jak sugerowałeś, dzięki.
Dan Kohn
3

Jestem kilka lat spóźniony na imprezę, ale podobało mi się to jedno-liniowe rozwiązanie, w którym szyny zawierały wszystko, aby uwzględnić wszystko w aplikacji / pracownikach / obawach:

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

Jazz
źródło
-2

A co z require_relative *Dir['relative path']:?

Aleksander
źródło
1
Wymagaj krewnego nie bierze wielu plików: ruby-doc.org/core-2.1.2/Kernel.html#method-i-require_relative
fabriciofreitag
OK, ale w moim przykładzie tak nie jest. „*” Zmienia arity na 1. Działa jako wielokrotne wywołanie wymagania_relatywnej.
Aleksander
1
„*” Zmienia arity na 1 - Co masz na myśli? require_relative *Dir['*.rb']działa, jeśli jest tylko jeden skrypt ruby. Ale jeśli znaleziono wiele skryptów ruby, dostajeszrequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
knut