วิธีที่ดีที่สุดที่จะต้องใช้ไฟล์ทั้งหมดจากไดเรกทอรีในทับทิม?


351

วิธีที่ดีที่สุดที่จะต้องใช้ไฟล์ทั้งหมดจากไดเรกทอรีในทับทิมคืออะไร?


คุณสามารถสร้างไฟล์ที่มีชื่อเดียวกันของไดเรกทอรีและต้องการไฟล์ทั้งหมด RSpec ทำเช่นนี้
pedromanoel

คำตอบ:


462

เกี่ยวกับ:

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

18
ตาม Pickaxe ส่วนขยาย. rb เป็นทางเลือก ในทางเทคนิคแล้วมันจะเปลี่ยนความหมาย: "require 'foo.rb'" ต้องการ foo.rb ในขณะที่ "require 'foo'" อาจต้องใช้ foo.rb, foo.so หรือ foo.dll
Sam Stokes

28
มี gotcha ที่บอบบางที่จะไม่ดึงส่วนขยายออก หากบางส่วนของการเรียกรหัสต้องใช้ 'foo' แล้ว ruby ​​จะโหลดไฟล์เดิมอีกครั้งซึ่งอาจทำให้เกิดข้อผิดพลาดปลอม ฉันเพิ่มคำตอบของตัวเองซึ่งอธิบายและแสดงวิธีตัดส่วนขยาย
Pete Hodgson

4
@Pete นี้ยังคงเป็นจริงหรือไม่? ดูความคิดเห็นของ Reneด้านล่าง
Andres Riofrio

5
สิ่งนี้อาจเห็นได้ชัด แต่สิ่งที่ควรสังเกตคือการปล่อยไฟล์. rb นั้นต้องใช้ไฟล์ที่ไม่ใช่. rb ใน dir ซึ่งอาจไม่ต้องการ
2398029

10
คำแนะนำของ @ PeteHodgson ไม่ถูกต้อง รูบี้requireไม่สับสนกับการมีหรือไม่มี.rbนามสกุล ทดสอบกับ MRI 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 }
Chris

6
นอกจากนี้ยังมี require_relative
maasha

30
หากคุณกำลังใช้> = ทับทิม 2.0 คุณสามารถใช้แทน__dir__ File.dirname(__FILE__)
Christian Bankester

3
@maasha คุณrequire_relativeจะใช้เพื่อกำหนดไฟล์ทั้งหมดในไดเรกทอรีได้อย่างไร?
David Moles

101

ลองใช้ require_all gem:

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

มันช่วยให้คุณ:

require_all 'path/to/directory'

ฉันจำเป็นต้องรวมรุ่น ActiveRecord ทั้งหมดของฉัน, อัญมณี require_all หาการพึ่งพาทั้งหมดและต้องการมันอย่างสมบูรณ์ ขอบคุณ!
panupan

2
@panupan เพิ่งทราบว่าการrequire_allแก้ปัญหาการพึ่งพาของวงจรแก้ไขปัญหาในซอร์สโค้ดของคุณ: คุณมีไฟล์ทับทิมที่ไม่ต้องการการพึ่งพา วิธีนี้จะปิดประตูเมื่อมีการโหลดมีดผ่าตัดทำให้คุณสามารถโหลดได้ทั้งหมดหรือไม่ใช้เลย นั่นไม่ใช่ปัญหาในห้องสมุดขนาดเล็ก แต่เป็นการตัดสินใจที่คุณควรทำอย่างมีสติ
sheldonh

มันไม่มีความหมายที่จะขยายแอปของคุณด้วยอัญมณีที่คุณสามารถแทนที่ด้วยบรรทัดของโค้ด สิ่งนี้จะเพิ่มความเร็วในการโหลดแอพของคุณและทำให้เกิดข้อบกพร่องมากขึ้นในระยะยาว
Pere Joan Martorell

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
Derek

13
การทดสอบของฉันแสดงให้เห็นว่าดีเร็กกล่าวว่าrequire "foo.rb"; require "foo";จะโหลดfoo.rbเพียงครั้งเดียว
Rene Saarsoo

@ PeteHodgson- คุณสำรองได้ไหม
Yarin

4
ไม่รูบี้requireไม่สับสนกับการมีหรือไม่มี.rbนามสกุล ทดสอบกับ MRI 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รับบล็อกเป็นอาร์กิวเมนต์

เมธอด (: require) จะส่งคืนเมธอด require

& method (: ต้องการ) จะแปลงวิธีการเป็นกลุ่ม


2
นี่คือรหัสที่สวยงาม ฉันชอบที่ไม่มีบล็อกที่มองเห็นได้
Nate Symer

1
Dir.glob( File.join( File.dirname(__FILE__), '{lib,addons}', 'subfolder', '**', '*.rb' ), &method(:require) )กำจัดการพึ่งพาแพลตฟอร์ม (เช่น '/' หรือ '\') ทำได้ดี. ขอบคุณ
Ivan Black

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

สิ่งนี้จะทำงานซ้ำในเครื่องของคุณและรีโมต (Like 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

ขอบคุณสำหรับคำแนะนำ; ฉันแก้ไขเพื่อรวมความคิดเห็นของคุณ
Dan Kohn

การใช้ฟอร์เวิร์ดสแลช (/) สำหรับไดเรกทอรีย่อยภายใต้ Rails.root ตัวอย่างเช่นRails.root.join('/lib')ไม่สร้างเส้นทางที่ถูกต้อง ผมพบว่าหนึ่งในการทำงานอย่างถูกต้อง:Dir[Rails.root.join('lib', 'ext', '*.rb')].each { |file| require file }
Jignesh Gohel

@Jiggneshh Gohel ฉันลบเครื่องหมายทับตามที่คุณแนะนำขอบคุณ
Dan Kohn

3

ฉันไปปาร์ตี้ไม่กี่ปี แต่ฉันชอบวิธีแก้ปัญหาแบบบรรทัดเดียวที่ฉันใช้เพื่อให้ rails รวมทุกอย่างในแอพ / คนงาน / ข้อกังวล:

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

ตกลง แต่ในตัวอย่างของฉันมันไม่ใช่ การ '*' เปลี่ยน arity เป็น 1 มันทำหน้าที่เหมือนกับการเรียกหลายครั้งเพื่อ require_relative
Aleksander

1
การเปลี่ยนแปลง '*' arity เป็น 1 - คุณหมายถึงอะไร require_relative *Dir['*.rb']ทำงานถ้ามีเพียงหนึ่งทับทิมสคริปต์ แต่ถ้าพบสคริปต์ทับทิมหลายตัวคุณจะได้รับrequire_relative': wrong number of arguments (4 for 1) (ArgumentError)
knut
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.