File.expand_path (“ ../../ Gemfile”, __FILE__) ทำงานอย่างไร ไฟล์อยู่ที่ไหน


84

ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)

ฉันแค่พยายามเข้าถึงไฟล์. rb จากไดเร็กทอรีและบทช่วยสอนกำลังบอกให้ใช้โค้ดนี้ แต่ฉันไม่เห็นว่ามันค้นหาไฟล์ gem ได้อย่างไร


คำตอบ:


195
File.expand_path('../../Gemfile', __FILE__)

เป็นสำนวน Ruby ที่ค่อนข้างน่าเกลียดสำหรับการรับเส้นทางสัมบูรณ์ไปยังไฟล์เมื่อคุณทราบเส้นทางที่สัมพันธ์กับไฟล์ปัจจุบัน อีกวิธีหนึ่งในการเขียนคือ:

File.expand_path('../Gemfile', File.dirname(__FILE__))

ทั้งคู่น่าเกลียด แต่ตัวแปรแรกสั้นกว่า อย่างไรก็ตามตัวแปรแรกยังไม่ใช้งานง่ายจนกว่าคุณจะได้รับความยุ่งยาก ทำไมต้องพิเศษ..? (แต่ตัวแปรที่สองอาจให้เบาะแสว่าเหตุใดจึงจำเป็นต้องใช้)

นี่คือวิธีการทำงาน: File.expand_pathคืนค่าพา ธ สัมบูรณ์ของอาร์กิวเมนต์แรกโดยสัมพันธ์กับอาร์กิวเมนต์ที่สอง (ซึ่งเป็นค่าเริ่มต้นของไดเร็กทอรีการทำงานปัจจุบัน) __FILE__คือพา ธ ไปยังไฟล์ที่โค้ดอยู่เนื่องจากอาร์กิวเมนต์ที่สองในกรณีนี้คือพา ธ ไปยังไฟล์และFile.expand_pathถือว่าไดเร็กทอรีเราต้องติดส่วนเสริม..ในพา ธ เพื่อให้พา ธ ถูกต้อง นี่คือวิธีการทำงาน:

File.expand_pathถูกนำไปใช้โดยทั่วไปเช่นนี้ (ในรหัสต่อไปนี้pathจะมีค่า../../Gemfileและrelative_toจะมีค่าเป็น/path/to/file.rb):

def File.expand_path(path, relative_to=Dir.getwd)
  # first the two arguments are concatenated, with the second argument first
  absolute_path = File.join(relative_to, path)
  while absolute_path.include?('..')
    # remove the first occurrence of /<something>/..
    absolute_path = absolute_path.sub(%r{/[^/]+/\.\.}, '')
  end
  absolute_path
end

(มีอีกเล็กน้อยมันขยาย~ไปยังโฮมไดเร็กทอรีและอื่น ๆ - อาจมีปัญหาอื่น ๆ เกี่ยวกับโค้ดด้านบน)

การก้าวผ่านการโทรไปยังรหัสด้านบนabsolute_pathก่อนอื่นจะได้รับค่า/path/to/file.rb/../../Gemfileจากนั้นสำหรับแต่ละรอบในลูปครั้งแรก..จะถูกลบออกพร้อมกับองค์ประกอบเส้นทางที่อยู่ข้างหน้า ครั้งแรก/file.rb/..จะถูกลบออกแล้วในรอบต่อไปจะถูกลบออกและเราได้รับ/to/../path/Gemfile

หากต้องการทำให้เรื่องยาวสั้นFile.expand_path('../../Gemfile', __FILE__)เป็นเคล็ดลับในการรับเส้นทางที่แน่นอนของไฟล์เมื่อคุณทราบเส้นทางที่สัมพันธ์กับไฟล์ปัจจุบัน ความพิเศษ..ในเส้นทางสัมพัทธ์คือการกำจัดชื่อของไฟล์ใน__FILE__.

ใน Ruby 2.0 มีKernelฟังก์ชันที่เรียก__dir__ว่าใช้งานเป็นFile.dirname(File.realpath(__FILE__)).


2
มีเหตุผลใดบ้างที่คุณไม่ควรใช้ 'require_relative' นอกเหนือจากความไม่เข้ากันกับ Ruby 1.9.2 รุ่นก่อน
Danny Andrews

9
สำหรับ Ruby 2.0 คุณสามารถใช้ได้File.expand_path('../Gemfile',__dir__)
Phrogz

บรรทัดนี้จาก Theo ในที่สุดก็คลิกให้ฉันFile.expand_path assumes a directoryแม้ว่า__FILE__จะไม่ใช่ไดเร็กทอรี สำหรับสิ่งที่ควรใช้__dir__ซึ่งจริงๆแล้วคือไดเร็กทอรี
mbigras

9

ข้อมูลอ้างอิงสองรายการ:

  1. ไฟล์ :: เอกสารวิธีการ expand_path
  2. วิธีการ__FILE__ทำงานใน Ruby

วันนี้ฉันเจอสิ่งนี้:

boot.rb คอมมิตใน Rails Github

หากคุณขึ้นสองไดเร็กทอรีจาก boot.rb ในแผนผังไดเร็กทอรี:

/ railties / lib / ราง / เครื่องกำเนิดไฟฟ้า / ราง / แอป / เทมเพลต

คุณเห็น Gemfile ซึ่งทำให้ฉันเชื่อว่าFile.expand_path("../../Gemfile", __FILE__)การอ้างอิงไฟล์ต่อไปนี้:/path/to/this/file/../../Gemfile


ขอบคุณสำหรับโพสต์ แต่สิ่งนี้มาจากบทช่วยสอน gembundler ดังนั้นฉันจึงพยายามทำความเข้าใจว่ามันเป็นอย่างไร :)
thenengah
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.