ความแตกต่างระหว่าง require_relative และต้องการในทับทิมคืออะไร?


302

ความแตกต่างระหว่างrequire_relativeและrequireในทับทิมคืออะไร?


9
ก่อน 1.9.2 มีความจำเป็นในการ require_relative $:ไม่เพราะไดเรกทอรีปัจจุบันของสคริปต์อยู่ใน ดูstackoverflow.com/questions/2900370
Nakilon

1
require_relative ต้องการไฟล์ที่ชี้ไปที่สัมพันธ์กับไฟล์ที่เรียกมันโดยเฉพาะ จำเป็นต้องมีไฟล์ที่รวมอยู่ใน $ LOAD_PATH
Donato

บทความที่มีประโยชน์เกี่ยวกับความแตกต่าง => medium.com/@ellishim/…
ahmed hamdy

คำตอบ:


298

เพียงดูที่เอกสาร :

require_relativeเติมเต็มวิธีการ builtin requireโดยให้คุณโหลดไฟล์ที่เกี่ยวข้องกับไฟล์ที่มีrequire_relativeคำสั่ง

ตัวอย่างเช่นหากคุณมีคลาสทดสอบหน่วยในไดเรกทอรี "test" และข้อมูลสำหรับพวกเขาภายใต้ไดเรกทอรี "test / data" การทดสอบแล้วคุณอาจใช้บรรทัดเช่นนี้ในกรณีทดสอบ:

require_relative "data/customer_data_1"

28
มีความแตกต่างระหว่างrequire './file.rb'และrequire_relative 'file.rb'?
Ciro Santilli 郝海东冠状病六四事件法轮功

69
@CiroSantilli ใช่ require_relativeช่วยให้คุณ "โหลดไฟล์ที่สัมพันธ์กับไฟล์ที่มีrequire_relativeคำสั่ง " ด้วยrequire, ./หมายถึงพา ธ ที่สัมพันธ์กับไดเร็กทอรีการทำงานปัจจุบันของคุณ
Ajedi32

16
ฉันคิดว่ามันสำคัญกว่าที่จะต้องทราบว่าrequire strจะค้นหาไดเรกทอรีใน $ LOAD_PATH เสมอ คุณควรใช้require_relativeเมื่อไฟล์ที่คุณต้องการโหลดนั้นมีอยู่บางแห่งที่เกี่ยวข้องกับไฟล์ที่เรียกใช้การโหลด สำรองrequireสำหรับการอ้างอิง "ภายนอก"
rthbound

97

require_relative เป็นเซตย่อยที่สะดวกสบายของ require

require_relative('path')

เท่ากับ:

require(File.expand_path('path', File.dirname(__FILE__)))

ถ้า__FILE__มีการกำหนดไว้หรือเพิ่มเป็นLoadErrorอย่างอื่น

นี่ก็หมายความว่า:

  • require_relative 'a'และrequire_relative './a'ต้องการสัมพันธ์กับไฟล์ปัจจุบัน ( __FILE__)

    นี่คือสิ่งที่คุณต้องการใช้เมื่อต้องการภายในไลบรารีของคุณเนื่องจากคุณไม่ต้องการให้ผลลัพธ์ขึ้นอยู่กับไดเรกทอรีปัจจุบันของผู้โทร

  • eval('require_relative("a.rb")')ยกLoadErrorเพราะไม่ได้กำหนดไว้ภายใน__FILE__eval

    นี่คือเหตุผลที่คุณไม่สามารถใช้require_relativeในการทดสอบ RSpec ซึ่งได้รับevaled

การดำเนินการต่อไปนี้เป็นไปได้เฉพาะกับrequire:

  • require './a.rb'ต้องสัมพันธ์กับไดเรกทอรีปัจจุบัน

  • require 'a.rb'ใช้เส้นทางการค้นหา ( $LOAD_PATH) เพื่อต้องการ ไม่พบไฟล์ที่เกี่ยวข้องกับไดเรกทอรีหรือเส้นทางปัจจุบัน

    นี้ไม่ได้เป็นไปได้ด้วยrequire_relativeเพราะเอกสารกล่าวว่าการค้นหาเส้นทางที่จะเกิดขึ้นเมื่อ "ชื่อไฟล์ไม่ได้มีมติให้เส้นทางที่แน่นอน" (คือเริ่มต้นด้วย/หรือ./หรือ../) File.expand_pathซึ่งมักจะเป็นกรณีที่

การดำเนินการต่อไปนี้เป็นไปได้สำหรับทั้งคู่ แต่คุณจะต้องการใช้requireเนื่องจากมีขนาดสั้นลงและมีประสิทธิภาพมากขึ้น:

  • require '/a.rb'และrequire_relative '/a.rb'ทั้งสองต้องการเส้นทางที่แน่นอน

อ่านแหล่งที่มา

เมื่อเอกสารไม่ชัดเจนฉันขอแนะนำให้คุณดูที่แหล่งที่มา (สลับแหล่งที่มาในเอกสาร) ในบางกรณีจะช่วยให้เข้าใจสิ่งที่เกิดขึ้น

จำเป็นต้อง:

VALUE rb_f_require(VALUE obj, VALUE fname) {
  return rb_require_safe(fname, rb_safe_level());
}

require_relative:

VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
    VALUE base = rb_current_realfilepath();
    if (NIL_P(base)) {
        rb_loaderror("cannot infer basepath");
    }
    base = rb_file_dirname(base);
    return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}

สิ่งนี้ทำให้เราสามารถสรุปได้ว่า

require_relative('path')

เหมือนกับ:

require(File.expand_path('path', File.dirname(__FILE__)))

เพราะ:

rb_file_absolute_path   =~ File.expand_path
rb_file_dirname1        =~ File.dirname
rb_current_realfilepath =~ __FILE__

74

จาก Ruby API :

require_relative เติมเต็มวิธีการ builtin ที่ต้องการโดยช่วยให้คุณสามารถโหลดไฟล์ที่เกี่ยวข้องกับไฟล์ที่มีคำสั่ง require_relative

เมื่อคุณใช้ต้องโหลดไฟล์คุณมักจะเข้าถึงฟังก์ชั่นที่ติดตั้งอย่างเหมาะสมและเข้าถึงได้ในระบบของคุณ จำเป็นต้องมีไม่ได้เป็นทางออกที่ดีสำหรับการโหลดไฟล์ภายในรหัสของโครงการ สิ่งนี้อาจมีประโยชน์ในระหว่างขั้นตอนการพัฒนาสำหรับการเข้าถึงข้อมูลทดสอบหรือแม้แต่การเข้าถึงไฟล์ที่ "ล็อค" อยู่ในโครงการไม่ได้มีไว้สำหรับใช้ภายนอก

ตัวอย่างเช่นหากคุณมีคลาสทดสอบหน่วยในไดเรกทอรี "test" และข้อมูลสำหรับพวกเขาภายใต้ไดเรกทอรี "test / data" การทดสอบแล้วคุณอาจใช้บรรทัดเช่นนี้ในกรณีทดสอบ:

require_relative "data/customer_data_1" 

เนื่องจากทั้ง "ทดสอบ" หรือ "ทดสอบ / ข้อมูล" ไม่น่าจะอยู่ในเส้นทางห้องสมุดของรูบี้ (และด้วยเหตุผลที่ดี) ความต้องการปกติจึงไม่สามารถหาได้ require_relative เป็นทางออกที่ดีสำหรับปัญหานี้โดยเฉพาะ

คุณอาจรวมหรือละเว้นส่วนขยาย (.rb หรือ. so) ของไฟล์ที่คุณกำลังโหลด

เส้นทางจะต้องตอบสนองต่อ to_str

คุณสามารถค้นหาเอกสารได้ที่http://extensions.rubyforge.org/rdoc/classes/Kernel.html


50

สรุป

ใช้requireสำหรับอัญมณีที่ติดตั้ง

ใช้require_relativeสำหรับไฟล์ในเครื่อง

requireใช้ของคุณ$LOAD_PATHเพื่อค้นหาไฟล์
require_relativeใช้ตำแหน่งปัจจุบันของไฟล์โดยใช้คำสั่ง


จำเป็นต้อง

ต้องอาศัยคุณติดตั้ง (เช่นgem install [package]) แพคเกจบางแห่งในระบบของคุณสำหรับการทำงานที่

เมื่อใช้requireคุณสามารถใช้./รูปแบบ "" สำหรับไฟล์ในไดเรกทอรีปัจจุบันได้require "./my_file"แต่นั่นไม่ใช่วิธีปฏิบัติทั่วไปหรือแบบที่แนะนำและคุณควรใช้require_relativeแทน

require_relative

ซึ่งหมายถึงรวมถึงไฟล์ 'สัมพันธ์กับตำแหน่งของไฟล์ที่มีคำสั่ง require_relative' ฉันโดยทั่วไปแนะนำว่าไฟล์ควร "ภายใน" ทรีไดเรกทอรีปัจจุบันตรงข้ามกับ "up" เช่นไม่ใช้

require_relative '../../../filename'

(เพิ่มขึ้น 3 ระดับไดเร็กทอรี) ภายในระบบไฟล์เนื่องจากมีแนวโน้มที่จะสร้างการพึ่งพาที่ไม่จำเป็นและเปราะบาง อย่างไรก็ตามในบางกรณีหากคุณ 'ลึก' อยู่ในแผนผังไดเรกทอรีแล้ว "ขึ้นและลง" สาขาต้นไม้ไดเรกทอรีอื่นอาจจำเป็น บางทีอาจจะมากกว่านั้นอย่าใช้ require_relative สำหรับไฟล์ที่อยู่นอกพื้นที่เก็บข้อมูลนี้ (สมมติว่าคุณใช้ git ซึ่งส่วนใหญ่เป็นมาตรฐานแบบพฤตินัย ณ จุดนี้ปลายปี 2018)

โปรดทราบว่าrequire_relativeใช้ไดเรกทอรีปัจจุบันของไฟล์ที่มีคำสั่งrequire_relative (ดังนั้นไม่จำเป็นต้องมีไดเรกทอรีปัจจุบันของคุณที่คุณใช้คำสั่งจาก) สิ่งนี้จะช่วยให้require_relativeเส้นทาง "เสถียร" ตามที่สัมพันธ์กับไฟล์ที่ต้องการในลักษณะเดียวกันเสมอ


27

คำตอบที่ถูกต้อง แต่เป็นเรื่องทางเทคนิคอย่างลึกซึ้ง สำหรับคนที่ใหม่กว่าสำหรับ Ruby:

  • require_relative ส่วนใหญ่จะถูกใช้เพื่อนำรหัสจากไฟล์อื่นที่คุณเขียน

ตัวอย่างเช่นถ้าคุณมีข้อมูลใน~/my-project/data.rbและคุณต้องการที่จะรวมว่าใน~/my-project/solution.rb? ในการที่คุณจะเพิ่มsolution.rbrequire_relative 'data'

เป็นสิ่งสำคัญที่จะต้องทราบว่าไฟล์เหล่านี้ไม่จำเป็นต้องอยู่ในไดเรกทอรีเดียวกัน require_relative '../../folder1/folder2/data'ถูกต้องเช่นกัน

  • require ส่วนใหญ่จะถูกนำมาใช้เพื่อนำรหัสจากห้องสมุดคนอื่นเขียน

ตัวอย่างเช่นถ้าคุณต้องการใช้ฟังก์ชันตัวช่วยอย่างใดอย่างหนึ่งที่มีให้ในactive_supportไลบรารี คุณจะต้องติดตั้งอัญมณีที่มีแล้วในแฟ้มgem install activesupportrequire 'active_support'

require 'active_support/all'
"FooBar".underscore

กล่าวว่าแตกต่าง -

  • require_relative ต้องใช้ไฟล์ที่ชี้เฉพาะที่สัมพันธ์กับไฟล์ที่เรียกมัน

  • require$LOAD_PATHต้องใช้ไฟล์ที่รวมอยู่ใน


3
ฉันจะโหวตคำตอบนี้และนำไปสู่จุดสูงสุดได้อย่างไรดังนั้นผู้เข้าชมหน้าคำถามนี้ทุกคนจะได้รับคำตอบที่ชัดเจนและเข้าใจได้ทันทีโดยไม่ทำให้สมองแตก
TiredOfProgramming

16

ฉันเพิ่งเห็นรหัสของ RSpec มีความคิดเห็นเกี่ยวกับrequire_relativeค่าคงที่ O (1) และrequireเส้นตรง O (N) ดังนั้นอาจจะแตกต่างกันคือเป็นคนที่ต้องการมากกว่าrequire_relativerequire


1
น่าสนใจ ฉันลงจอดที่นี่เพื่อค้นหาข้อมูลเกี่ยวกับการเปรียบเทียบความเร็ว ฉันคิดว่าrequire_relativeมันเร็วกว่าเพราะโหลดเดอร์ไม่จำเป็นต้องข้ามพา ธ โหลดเพื่อค้นหาไฟล์ เป็นหลักrequire_relativeให้การเชื่อมโยงโดยตรง
Clint Pachl

disscussion ช่วงต้นเกี่ยวกับความเร็ว require_relativeและ RSpec เปลี่ยนแปลง
Clint Pachl

1

ฉันต้องการเพิ่มว่าเมื่อใช้ Windows ที่คุณสามารถใช้require './1.rb'ถ้าสคริปต์ที่จะดำเนินการในท้องถิ่นหรือจากไดรฟ์เครือข่ายที่แมป แต่เมื่อเรียกใช้จาก UNC เส้นทางที่คุณจำเป็นต้องใช้\\servername\sharename\folderrequire_relative './1.rb'

ฉันไม่ได้เข้าไปมีส่วนร่วมในการอภิปรายเพื่อใช้ด้วยเหตุผลอื่น


ฉันอยากจะรู้ว่าคุณจะโหลดrequire_relativeไฟล์ที่คุณจะกรุณาโยนความคิดนี้ stackoverflow.com/questions/43487784/...
Emjey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.