Чи існує якась велика різниця між програмами Ruby on Rails load
та require
у них? Або вони обидва мають однакову функціональність?
Чи існує якась велика різниця між програмами Ruby on Rails load
та require
у них? Або вони обидва мають однакову функціональність?
Відповіді:
require
шукає бібліотеку за всіма визначеними шляхами пошуку, а також додає .rb або .so до імені файлу, яке ви вводите. Це також гарантує, що бібліотека включається лише один раз. Отже, якщо для вашої програми потрібні бібліотеки A та B та бібліотека B, бібліотека запитів A теж A буде завантажена лише один раз.
З load
вас виникла необхідність створення повне ім'я бібліотеки і завантажуються кожен раз , коли ви називаєте load
- навіть якщо він вже перебуває в пам'яті.
require
відстежує те, що вже було завантажено через $LOADED_FEATURES
( $"
) глобальний масив, який load
ігнорує.
Ще одна відмінність між Kernel#require
іKernel#load
полягає в тому, що Kernel#load
приймає необов’язковий другий аргумент, який дозволяє обернути завантажений код в анонімний порожній модуль.
На жаль, це не дуже корисно. По-перше, load
редагованому коду легко вирватися з модуля, просто отримавши доступ до глобального простору імен, тобто вони все одно можуть мавпати щось подібне class ::String; def foo; end end
. А по-друге, load
не повертає модуль, в який він загортає код, тому вам, по суті, доведеться виловлювати його ObjectSpace::each_object(Module)
вручну.
Kernel#load
мав ідеї, мав інший аргумент
load
редагованому коду легко вирватися з модуля, просто отримавши доступ до глобального простору імен, тобто вони все одно можуть мавпати щось подібне class ::String; def foo; end end
. А по-друге, load
не повертає модуль, в який він загортає код, тому вам, по суті, доведеться виловлювати його ObjectSpace::each_object(Module)
вручну.
Я запускав програму Rails, і в Gemfile у мене був спеціальний власний камінь, який я створив із опцією "require: false". Тепер, коли я завантажив сервер Rails або консоль Rails, я зміг зажадати самоцвіт в ініціалізаторі, і дорогоцінний камінь було завантажено. Однак, коли я провів перевірку характеристик специфікації з rspec та capybara, я отримав помилку завантаження. І я був абсолютно здивований, чому самоцвіт не був знайдений у $ LOAD_PATH під час запуску тесту.
Тож я переглянув усі різні способи взаємодії рубігів та пакета, які завантажуються, вимагають. І це короткий опис моїх висновків, які допомогли мені знайти рішення моєї конкретної проблеми:
навантаження
1) Ви можете передати йому абсолютний шлях до рубінового файлу, і він виконає код у цьому файлі.
load('/Users/myuser/foo.rb')
2) Ви можете пройти відносний шлях до завантаження. Якщо ви знаходитесь в тому ж каталозі, що і файл, він знайде його:
> load('./foo.rb')
foo.rb loaded!
=> true
Але якщо ви спробуєте завантажити файл із іншого каталогу за допомогою load (), він не знайде його з відносним шляхом на основі поточного робочого каталогу (наприклад, /):
> load('./foo.rb')
LoadError: cannot load such file -- foo.rb
3) Як показано вище, load завжди повертає true (якщо файл не вдалося завантажити, він піднімає a LoadError
).
4) Імпортуються глобальні змінні, класи, константи та методи, але не локальні змінні.
5) Двічі викликавши навантаження на один і той самий файл, буде виконано код у цьому файлі двічі. Якщо вказаний файл визначає константу, він визначить цю константу двічі, що видасть попередження.
6) $ LOAD_PATH - масив абсолютних шляхів. Якщо ви передаєте завантаження лише імені файлу, він прокручуватиме $ LOAD_PATH і шукатиме файл у кожному каталозі.
> $LOAD_PATH.push("/Users/myuser")
> load('foo.rb')
foo.rb loaded!
=> true
вимагати
1) Двічі вимагаючи виклику одного і того ж файлу, виконується лише один раз. Також досить розумно не завантажувати один і той же файл двічі, якщо ви посилаєтесь на нього один раз із відносним шляхом та один раз із абсолютним шляхом.
2) вимагати повернення true, якщо файл був виконаний, і false, якщо його не було.
3) require відстежує, які файли вже завантажені в глобальну змінну $ LOADED_FEATURES.
4) Вам не потрібно включати розширення файлу:
require 'foo'
5) require буде шукати foo.rb, а також динамічні файли бібліотеки, такі як foo.so, foo.o або foo.dll. Ось як ви можете зателефонувати коду С із рубіну.
6) require не перевіряє поточний каталог, оскільки поточний каталог за замовчуванням не знаходиться в $ LOAD_PATH.
7) require_relative бере шлях відносно поточного файлу, а не робочого каталогу процесу.
Рубігеми
1) Rubygems - це менеджер пакетів, призначений для легкого управління встановленням бібліотек Ruby, які називаються gems.
2) Він упаковує свій вміст як zip-файл, що містить купу рубінових файлів та / або динамічних бібліотечних файлів, які можна імпортувати за допомогою вашого коду, разом з деякими метаданими.
3) Rubygems замінює метод за замовчуванням require на власну версію. Ця версія переглядатиме ваші встановлені дорогоцінні камені на додаток до каталогів у $ LOAD_PATH. Якщо Rubygems знайде файл у ваших дорогоцінних каменях, він додасть цей самоцвіт до вашого $ LOAD_PATH.
4) Команда gem install встановлює всі залежності gem і встановлює їх. Насправді він встановлює всі залежності дорогоцінного каменя, перш ніж встановлювати сам камінь.
Пакувальник
1) Bundler дозволяє вказати всі дорогоцінні камені, які потрібні вашому проекту, а також, які версії цих дорогоцінних каменів. Потім команда bundle встановлює всі ці дорогоцінні камені та їх залежності.
2) Ви вказуєте, які дорогоцінні камені вам потрібні у файлі під назвою Gemfile.
3) Команда bundle також встановлює всі дорогоцінні камені, перелічені в Gemfile.lock, у певних перелічених версіях.
4) Поставивши bundle exec перед командою, наприклад bundle exec rspec, гарантує, що require завантажить версію дорогоцінного каменя, вказану у вашому Gemfile.lock.
Рейки та набір
1) У config / boot.rb потрібно виконати 'bundler / setup'. Бандлер гарантує, що Рубі може знайти всі дорогоцінні камені в Gemfile (і всі їх залежності). require 'bundler / setup' автоматично виявить ваш Gemfile і зробить усі дорогоцінні камені у вашому Gemfile доступними для Ruby (у технічному плані це ставить дорогоцінні камені "на шлях завантаження"). Ви можете сприймати це як додавання деяких додаткових повноважень, щоб вимагати "рубімів".
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
2) Тепер, коли ваш код доступний Ruby, ви можете зажадати дорогоцінні камені, які вам потрібні. Наприклад, ви можете вимагати "синатра". Якщо у вас багато залежностей, ви можете сказати "вимагати всіх дорогоцінних каменів у моєму Gemfile". Для цього поставте наступний код відразу ж після вибору 'bundler / setup':
Bundler.require(:default)
3) За замовчуванням для виклику Bundler.require потрібен кожен дорогоцінний камінь у вашому Gemfile. Якщо в рядку в Gemfile написано gem 'foo',: require => false, тоді він переконається, що foo встановлено, але він не викликає require. Вам потрібно буде зателефонувати require ('foo'), якщо ви хочете використовувати самоцвіт.
Отже, враховуючи цю широту знань, я повернувся до питання мого тесту і зрозумів, що я повинен явно вимагати самоцвіт у rails_helper.rb, оскільки Bundler.setup додав його до $ LOAD_PATH, але вимагає: false виключає Bundler.require вимагати цього явно . І тоді питання було вирішено.
require
,load
абоautoload
в Ruby?