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?


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 }

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 }

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'

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”).


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.


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 }

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__.


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.


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.


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 }


-2

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



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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.