Чи існує якась велика різниця між програмами 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?