Apa perbedaan antara require_relative dan butuhkan di Ruby?

302

Apa perbedaan antara require_relativedan requiredi Ruby?

agentbanks217
sumber
9
Sebelum 1.9.2 tidak perlu memerlukan_relatif, karena direktori skrip saat ini ada di $:. Lihat stackoverflow.com/questions/2900370
Nakilon
1
require_relative membutuhkan file yang secara khusus diarahkan ke file yang memanggilnya. mengharuskan membutuhkan file yang termasuk dalam $ LOAD_PATH.
Donato
artikel bermanfaat tentang perbedaan => medium.com/@ellishim/…
ahmed

Jawaban:

298

Lihat saja dokumen :

require_relativemelengkapi metode bawaan requiredengan memungkinkan Anda untuk memuat file yang relatif terhadap file yang berisi require_relativepernyataan.

Misalnya, jika Anda memiliki kelas uji unit dalam direktori "test", dan data untuk mereka di bawah direktori test "test / data", maka Anda dapat menggunakan baris seperti ini dalam case test:

require_relative "data/customer_data_1"
miku
sumber
28
Apakah ada perbedaan antara require './file.rb'dan require_relative 'file.rb'?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
69
@CiroSantilli Ya. require_relativememungkinkan Anda untuk "memuat file yang relatif terhadap file yang berisi require_relativepernyataan ". Dengan require, ./menunjukkan jalur yang relatif terhadap direktori kerja Anda saat ini.
Ajedi32
17
Saya pikir lebih penting untuk dicatat bahwa require strakan selalu mencari melalui direktori di $ LOAD_PATH. Anda harus menggunakan require_relativeketika file yang Anda perlu memuat ada di suatu tempat relatif terhadap file yang memanggil untuk memuat. Cadangan requireuntuk dependensi "eksternal".
rthbound
97

require_relative adalah bagian nyaman dari require

require_relative('path')

sama dengan:

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

jika __FILE__didefinisikan, atau memunculkan LoadErrorsebaliknya.

Ini menyiratkan bahwa:

  • require_relative 'a'dan require_relative './a'membutuhkan relatif ke file saat ini ( __FILE__).

    Ini adalah apa yang ingin Anda gunakan ketika memerlukan di dalam perpustakaan Anda, karena Anda tidak ingin hasilnya bergantung pada direktori pemanggil saat ini.

  • eval('require_relative("a.rb")')menimbulkan LoadErrorkarena __FILE__tidak didefinisikan di dalam eval.

    Inilah sebabnya mengapa Anda tidak dapat menggunakan require_relativedalam tes RSpec, yang menjadi evaled.

Operasi berikut hanya dapat dilakukan dengan require:

  • require './a.rb'membutuhkan relatif ke direktori saat ini

  • require 'a.rb'menggunakan jalur pencarian ( $LOAD_PATH) untuk meminta. Itu tidak menemukan file relatif terhadap direktori atau jalur saat ini.

    Ini tidak dimungkinkan dengan require_relativekarena dokumen mengatakan bahwa pencarian jalur hanya terjadi ketika "nama file tidak menyelesaikan ke jalur absolut" (yaitu dimulai dengan /atau ./atau ../), yang selalu menjadi kasus untuk File.expand_path.

Operasi berikut ini dimungkinkan dengan keduanya, tetapi Anda ingin menggunakannya requirekarena lebih pendek dan lebih efisien:

  • require '/a.rb'dan require_relative '/a.rb'keduanya membutuhkan jalur absolut.

Membaca sumbernya

Ketika dokumen tidak jelas, saya sarankan agar Anda melihat sumber (beralih sumber di dokumen). Dalam beberapa kasus, membantu memahami apa yang sedang terjadi.

memerlukan:

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());
}

Ini memungkinkan kita untuk menyimpulkan itu

require_relative('path')

sama dengan:

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

karena:

rb_file_absolute_path   =~ File.expand_path
rb_file_dirname1        =~ File.dirname
rb_current_realfilepath =~ __FILE__
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
74

Dari Ruby API :

require_relative melengkapi metode builtin mengharuskan dengan memungkinkan Anda untuk memuat file yang relatif terhadap file yang berisi pernyataan require_relative.

Ketika Anda menggunakan harus memuat file, Anda biasanya mengakses fungsionalitas yang telah diinstal dengan benar, dan dapat diakses, di sistem Anda. mengharuskan tidak menawarkan solusi yang baik untuk memuat file dalam kode proyek. Ini mungkin berguna selama fase pengembangan, untuk mengakses data uji, atau bahkan untuk mengakses file yang "dikunci" di dalam proyek, tidak dimaksudkan untuk penggunaan luar.

Misalnya, jika Anda memiliki kelas uji unit dalam direktori "test", dan data untuk mereka di bawah direktori test "test / data", maka Anda dapat menggunakan baris seperti ini dalam case test:

require_relative "data/customer_data_1" 

Karena baik "tes" atau "tes / data" kemungkinan berada di jalur perpustakaan Ruby (dan untuk alasan yang baik), kebutuhan normal tidak akan menemukannya. require_relative adalah solusi yang bagus untuk masalah khusus ini.

Anda dapat menyertakan atau menghilangkan ekstensi (.rb atau .so) dari file yang Anda muat.

path harus menanggapi to_str.

Anda dapat menemukan dokumentasi di http://extensions.rubyforge.org/rdoc/classes/Kernel.html

svilenv
sumber
50

Ringkasan

Gunakan requireuntuk permata yang terpasang

Gunakan require_relativeuntuk file lokal

requiremenggunakan Anda $LOAD_PATHuntuk menemukan file.
require_relativemenggunakan lokasi file saat ini menggunakan pernyataan


memerlukan

Perlu bergantung pada Anda telah menginstal (misalnya gem install [package]) paket di suatu tempat di sistem Anda untuk fungsionalitas itu.

Saat menggunakan requireAnda dapat menggunakan ./format " " untuk file di direktori saat ini, mis. require "./my_file"Tapi itu bukan praktik yang umum atau disarankan dan Anda harus menggunakannya require_relative.

require_relative

Ini berarti memasukkan file 'relatif ke lokasi file dengan pernyataan require_relative'. Saya biasanya merekomendasikan bahwa file harus "di dalam" pohon direktori saat ini sebagai lawan dari "naik", misalnya jangan gunakan

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

(naik 3 level direktori) dalam sistem file karena itu cenderung membuat dependensi yang tidak perlu dan rapuh. Namun dalam beberapa kasus jika Anda sudah 'dalam' di dalam pohon direktori maka "naik turun" cabang pohon direktori lain mungkin diperlukan. Mungkin lebih sederhana, jangan gunakan require_relative untuk file di luar repositori ini (dengan asumsi Anda menggunakan git yang sebagian besar merupakan standar de-facto pada saat ini, akhir 2018).

Catatan yang require_relativemenggunakan direktori file saat ini dengan pernyataan require_relative (jadi tidak harus direktori Anda saat ini dari mana Anda menggunakan perintah). Ini menjaga require_relativejalur "stabil" karena selalu relatif terhadap file yang membutuhkannya dengan cara yang sama.

Michael Durrant
sumber
27

Jawaban teratas benar, tetapi sangat teknis. Bagi mereka yang lebih baru ke Ruby:

  • require_relative kemungkinan besar akan digunakan untuk membawa kode dari file lain yang Anda tulis.

misalnya, bagaimana jika Anda memiliki data ~/my-project/data.rbdan Anda ingin memasukkannya ke dalam ~/my-project/solution.rb? di solution.rbAnda akan menambahkan require_relative 'data'.

Penting untuk dicatat bahwa file-file ini tidak perlu berada di direktori yang sama. require_relative '../../folder1/folder2/data'juga valid.

  • require kemungkinan besar akan digunakan untuk membawa kode dari perpustakaan yang ditulis orang lain.

misalnya, bagaimana jika Anda ingin menggunakan salah satu fungsi pembantu yang disediakan di active_supportperpustakaan? Anda harus menginstal gem dengan gem install activesupportdan kemudian dalam file require 'active_support'.

require 'active_support/all'
"FooBar".underscore

Kata berbeda--

  • require_relative membutuhkan file yang secara khusus diarahkan ke file yang memanggilnya.

  • requiremembutuhkan file yang disertakan dalam $LOAD_PATH.

common-nighthawk
sumber
3
Bagaimana saya bisa memilih jawaban ini dan membawanya ke atas, sehingga setiap pengunjung halaman pertanyaan ini akan mendapatkan jawaban yang jelas dan mudah dimengerti tanpa merusak otak mereka?
TiredOfProgramming
16

Saya baru saja melihat kode RSpec memiliki beberapa komentar tentang require_relativemenjadi O (1) konstan dan requiremenjadi O (N) linier. Jadi mungkin perbedaannya adalah yang require_relativelebih disukai daripada require.

mech
sumber
1
Menarik. Saya mendarat di sini mencari info tentang perbandingan kecepatan. Pemikiran saya adalah require_relativeitu lebih cepat karena loader tidak harus melintasi jalur beban untuk mencari file. Intinya, require_relativesediakan tautan langsung.
Clint Pachl
Diskusi awal tentang kecepatan require_relative dan RSpec changelog .
Clint Pachl
1

Saya ingin menambahkan bahwa ketika menggunakan Windows Anda dapat menggunakan require './1.rb'jika skrip dijalankan secara lokal atau dari drive jaringan yang dipetakan tetapi ketika dijalankan dari \\servername\sharename\folderjalur UNC yang perlu Anda gunakan require_relative './1.rb'.

Saya tidak bergaul dalam diskusi yang digunakan karena alasan lain.

Peter
sumber
Saya ingin tahu bagaimana Anda memuat require_relativefile Bisakah Anda memberikan ide di stackoverflow.com/questions/43487784/…
Emjey