Найкращий спосіб вимагати всіх файлів з каталогу в рубіні?


351

Який найкращий спосіб вимагати всіх файлів з каталогу в рубіні?


Ви можете створити файл з однаковою назвою каталогу та вимагати, щоб він вимагав усіх файлів. RSpec робить це.
pedromanoel

Відповіді:


462

Як щодо:

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

18
Відповідно до Pickaxe, розширення .rb необов’язкове. Технічно це змінює значення: "вимагати" foo.rb "" вимагає foo.rb, тоді як "вимагати" foo "" може вимагати foo.rb, foo.so або foo.dll.
Сем Стоукс

28
Є тонка готча, щоб не знімати розширення. Якщо в якійсь іншій частині викликів коду потрібен "foo", то ruby ​​знову завантажить той самий файл, що може призвести до помилкових помилок. Я додав власну відповідь, яка пояснює це і показує, як зняти розширення.
Піт Ходжсон

4
@Pete, це все-таки правда? Дивіться коментар Рене нижче.
Андрес Ріофріо

5
Це може бути очевидним, але варто зауважити, що для видалення .rb також потрібні будь-які файли, що не є .rb, в режимі dir, що може бути не бажаним.
user2398029

10
@ Пропозиція PeteHodgson є неточною. Ruby's requireне плутає наявність чи відсутність .rbрозширення. Тестували на МРТ 1.8.7-p374, 2.1.5 та 2.2.0 тестували. Ця міська легенда походить з Rails, де "розумне" автозавантаження демонструвало поведінку, яку він описує у старих версіях (і може все ще демонструвати її).
sheldonh

345

Якщо це каталог відносно файлу, який вимагає (наприклад, ви хочете завантажити всі файли в каталозі lib):

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

Редагувати: На підставі коментарів нижче оновлена ​​версія:

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

14
Ви також можете додати всі подібні довідникиDir[File.dirname(__FILE__) + '/support/**/*.rb'].each {|file| require file }
jspooner,

62
Напевно, безпечніше використовувати File.join, ніж робити припущення щодо косої риски вперед / назад:Dir[File.join(File.dirname(__FILE__), 'lib', '*.rb')].each {|file| require file }
Кріс

6
Є також
Requ_relative

30
Якщо ви використовуєте> = ruby ​​2.0, ви можете використовувати __dir__замість File.dirname(__FILE__).
Крістіан Банкістер

3
@maasha Як ви require_relativeвимагаєте вимагати всіх файлів у каталозі?
Девід Молес

101

Спробуйте Requemall дорогоцінний камінь:

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

Це дозволяє вам просто:

require_all 'path/to/directory'

Мені потрібно було включити всі мої моделі ActiveRecord, дорогоцінний камінь Requ_all розібрався в усіх залежностях і вимагав їх ідеально. Дякую!
панупан

2
@panupan Будьте в курсі, що require_allциклічне рішення залежності залежить від проблеми у вихідному коді: у вас є вихідні файли Ruby, які не потребують їх залежностей. Це закриває двері при завантаженні скальпелем, зобов’язуючи вас завантажувати все або нічого. Це не є проблемою в невеликих бібліотеках, але це рішення, яке ви повинні приймати свідомо.
sheldonh

Немає сенсу розсипати додаток дорогоцінними каменями, які ви можете просто замінити рядком коду. Це збільшує час завантаження вашої програми та створює більше помилок на тривалий термін.
Пер Джоан Марторелл

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

Якщо ви не знімете розширення, то, можливо, два рази вимагати один і той же файл (рубін не зрозуміє, що "foo" і "foo.rb" - це один і той же файл). Якщо два рази вимагати один і той самий файл, може призвести до помилкових попереджень (наприклад, "попередження: вже ініціалізована константа").


11
Це справді так? Документація говорить: Функція не буде завантажена, якщо її ім'я вже відображається у $ ". Ім'я файлу перетворюється на абсолютний шлях, тому" вимагаю "a"; вимагати "./a" "не завантажуватиме a.rb двічі. ruby-doc.org/core/classes/Kernel.html#M001418
Дерек

13
Моє тестування показує те саме, що сказав Дерек: require "foo.rb"; require "foo";завантажуватимуться foo.rbлише один раз.
Рене Саарсоо

@ PeteHodgson- Чи можете ви створити резервну копію?
Ярін

4
Ні. Рубі requireне бентежить наявність чи відсутність .rbрозширення. Тестували на МРТ 1.8.7-p374, 2.1.5 та 2.2.0. Ця міська легенда походить з Rails, де "розумне" автозавантаження демонструвало поведінку, описану в старих версіях (і може все ще проявляти її).
sheldonh

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

або, якщо ви хочете обширити файли для завантаження в певні папки:

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

пояснення:

Dir.glob в якості аргументу бере блок.

метод (: вимагає) поверне метод вимагати.

& method (: вимагати) перетворить метод у блок.


2
Це якийсь прекрасний код. Мені подобається, як немає видимих ​​блоків.
Нейт Симер

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )виключає залежність від платформи (наприклад, '/' або '\'). Добре працює. Дякую.
Іван Чорний

30

Найкращий спосіб - додати каталог до шляху завантаження, а потім requireбазову назву кожного файлу. Це тому, що ви хочете уникнути випадкового вимагання одного і того ж файлу двічі - часто це не призначена поведінка. Буде файл завантажений чи ні, залежить від того, чи requireбачив шлях, пройдений до нього раніше. Наприклад, цей простий сеанс irb показує, що ви можете помилково вимагати та завантажувати один і той же файл двічі.

$ 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

Зауважте, що перші два рядки повертаються, trueтобто один і той же файл завантажувались обидва рази. Коли шляхи використовуються, навіть якщо шляхи вказують на те саме місце, requireне знає, що файл вже був потрібний.

Тут замість цього ми додаємо каталог до шляху завантаження, а потім вимагаємо базове ім'я кожного * .rb-файлу всередині.

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

Якщо ви не переймаєтесь тим, що потрібен файл не один раз, або ви маєте намір просто завантажити вміст файлу, можливо, його loadслід використовувати замість require. Використовуйте навантаження в цьому випадку, оскільки воно краще виражає те, що ви намагаєтеся досягти. Наприклад:

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

14

Замість поєднання шляхів, як у деяких відповідях, я використовую File.expand_path:

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

Оновлення:

Замість використання File.dirnameви можете зробити наступне:

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

Де ..смужки імені файлу __FILE__.


це, безумовно, здається, і це найсвіжіша відповідь, спробувавши все інше, +1 дляFile.expand_path
SuckerForMayhem

Я точно вважаю за краще цю відповідь прийнятою. Різні Rails.root.joinвідповіді також працюють, якщо ви знаходитесь в рейках.
nzifnab

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

Це працюватиме рекурсивно на вашій локальній машині та на пульті (як Heroku), який не використовує відносних шляхів.


8

У Rails ви можете:

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

Оновлення: виправлено пропозицію @Jiggneshh Gohel для видалення косої риски.


Оскільки Rails.rootце Pathnameекземпляр, ви можете це зробити в будь-якому середовищі Ruby, а не лише Rails (NB Rails.root.join('lib/ext/*.rb')читає трохи приємніше)
DMKE,

Дякую за рекомендацію; Я редагував, щоб включити ваш коментар.
Дан Кон

Використання косої риски вперед (/) для підкаталогів під Rails.root, наприклад Rails.root.join('/lib'), не створює правильний шлях. Я виявив, що це працює правильно:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel

@Jiggneshh Gohel Я зняв косої риски, як ви запропонували, дякую.
Дан Кон

3

Я запізнююсь на кілька років, але мені подобається це однолінійне рішення, яке я використовував для отримання рейок, щоб включити все в додаток / працівників / проблеми:

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


-2

А що: require_relative *Dir['relative path']?


1
Потрібний родич не приймає декілька файлів: ruby-doc.org/core-2.1.2/Kernel.html#method-i-require_relative
fabriciofreitag

Гаразд, але в моєму прикладі це не так. '*' Змінює суворість на 1. Він працює як багаторазовий виклик на файл Requ_relative.
Олександр

1
"*" Змінює суворість на 1 - що ви маєте на увазі під цим? require_relative *Dir['*.rb']працювати, якщо є лише один ruby-скрипт. Але якщо знайдено кілька рубінових скриптів, ви отримаєтеrequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
knut
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.