Додавання каталогу до $ LOAD_PATH (Ruby)


96

Я бачив дві загальновживані методики додавання каталогу файлу, що виконується в даний момент, до $ LOAD_PATH (або $ :). Я бачу переваги цього, якщо ви не працюєте з дорогоцінним камінням. Очевидно, один здається багатослівним, ніж інший, але чи є причина переходити з одним на інший?

Перший, багатослівний метод (може бути надмірним):

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))

і більш прямий, швидкий і брудний:

$:.unshift File.dirname(__FILE__)

Будь-яка причина переходити з однією на іншу?


2
Трохи менш багатослівним версія багатослівний є:File.expand_path(File.dirname(__FILE__)).tap {|pwd| $LOAD_PATH.unshift(pwd) unless $LOAD_PATH.include?(pwd)}
Nathan Long

як щодо речення "якщо"? Як два вищезазначені можуть бути рівнозначними?
inger

Як хтось, хто прийшов сюди, щоб спробувати зрозуміти, як цим користуватися, це супер загадково. На прикладах я не бачу, звідки походить назва каталогу. Буду вдячний, якщо хтось зможе це пояснити.
SlySherZ

1
Використання __dir__(станом на Ruby 2.0) може зробити будь-який із них більш стислим.
Натан Лонг

Відповіді:


51

Я б сказав, перейдіть $:.unshift File.dirname(__FILE__)до іншого, просто тому, що я бачив набагато більше його використання в коді, ніж той $LOAD_PATH, і він також коротший!


Коли я вперше розпочав роботу з Ruby, я, очевидно, думав, що $ LOAD_PATH був кращим. Але після того, як ви закінчите статус початківця, я буду використовувати $ LOAD_PATH, лише якщо намагався зробити свій код більш читабельним для початківців. Мех це компроміс. Це залежить від того, наскільки "загальнодоступним" є код, до тих пір, поки використання пам’яті однакове для кожного, що, на мою думку, це по суті.
boulder_ruby

9
Це залежить від керівництва стилем для вашого проекту. Популярний посібник із стилю Ruby каже: "Уникайте використання спеціальних змінних у стилі Perl (наприклад, $ :, $; та ін.). Вони досить загадкові, і їх використання у будь-чому, окрім однолінійних скриптів, не рекомендується".
bobmagoo

152

Шлях завантаження Ruby дуже часто називають $:, але те, що він короткий, не робить його кращим. Якщо ви віддаєте перевагу ясності перед кмітливістю або якщо лаконічність сама по собі змушує вас свербіти, вам не потрібно робити це лише тому, що всі інші. Привітайтеся з ...

$LOAD_PATH

... і попрощатися з ...

# I don't quite understand what this is doing...
$:

29
Крім того, Google набагато складніше для рядків типу "$:", які містять лише символи.
DSimon

23

Я не дуже люблю "швидкий і брудний" шлях. Будь-хто новачок у Рубі буде обмірковувати, що $:.є.

Я вважаю це більш очевидним.

libdir = File.dirname(__FILE__)
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

Або якщо я дбаю про повний шлях ...

libdir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)

ОНОВЛЕННЯ 2009/09/10

Останнім часом я робив наступне:

$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
    $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

Я бачив це у цілій купі різних рубінових проектів під час перегляду GitHub.

Здається, це конвенція?


@LukeAntins, це справді чудово, але де мені "завантажити" load_path у додатку?
gaussblurinc

@gaussblurinc Десь "вгорі" вашої бібліотеки / програми, але це насправді залежить. Якщо у вас був binфайл, який завжди був відносно вашого, codeі він коли-небудь запускався binфайлом ... bootstrap у сміттєвому ящику. Якщо у вас є бібліотека, тоді завантажувальний код у верхній частині вашого коду бібліотеки, як у, lib/code.rbщоб отримати доступ до всього, що наведено нижче lib/code/. Сподіваюся, ця блукання допоможе!
Luke Antins

1
RuboCop повідомляє мені, що __dir__можна використовувати шлях до каталогу поточного файлу.
Рафаель

8

Якщо ви введете script/consoleсвій проект Rails і введете $:, ви отримаєте масив, який включає всі каталоги, необхідні для завантаження Ruby. Висновок від цієї маленької вправи полягає в тому, що $:це масив. В такому випадку ви можете виконувати на ньому такі функції, як попереднє додавання інших каталогів unshiftметодом або <<оператором. Як ви мали на увазі у своїй заяві $:і $LOAD_PATHє однаковими.

Недоліком швидкого та брудного способу, як ви згадали, є такий: якщо у вас вже є каталог у шляху завантаження, він повториться.

Приклад:

У мене є плагін, який я створив, називається todo. Мій каталог структурований так:

/ --- постачальник
  |
  | --- / плагіни
        |
        | --- / todo
              |
              | --- / lib
                    |
                    | --- / додаток
                          |
                          | --- / моделі
                          | --- / контролери
              |
              | --- / рейки
                    |
                    | --- init.rb

У файл init.rb я ввів такий код:

## In vendor/plugins/todo/rails/init.rb
    %w{ models controllers models }.each do |dir|
      path = File.expand_path(File.join(File.dirname(__FILE__), '../lib', 'app', dir))
      $LOAD_PATH << path
      ActiveSupport::Dependencies.load_paths << path
      ActiveSupport::Dependencies.load_once_paths.delete(path)
    end 

Зверніть увагу, як я вказую блоку коду виконувати дії всередині блоку з рядками "моделі", "контролери" та "моделі", де я повторюю "моделі". (FYI, %w{ ... }це просто ще один спосіб сказати Рубі тримати масив рядків). Коли я запускаю script/console, я набираю таке:

>> puts $:

І я набираю це так, щоб було легше читати вміст у рядку. Результат, який я отримую:

...
...
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/controllers
./Users/Me/mySites/myRailsApp/vendor/plugins/todo/lib/app/models

Як бачите, хоча це настільки простий приклад, який я міг створити, використовуючи проект, над яким я зараз працюю, якщо ви не будете обережні, швидкий і брудний шлях призведе до повторення шляхів. Більш довгий шлях перевірить повторювані шляхи та переконається, що вони не трапляються.

Якщо ви досвідчений програміст Rails, ви, мабуть, прекрасно уявляєте, що робите, і, швидше за все, не помилитеся, повторюючи шляхи. Якщо ти новачок, я піду довшим шляхом, поки ти не зрозумієш насправді, що робиш.


Ваша відповідь дуже корисна, а також добре пояснена. Запропоноване редагування: метод load_pathsі load_once_paths.deleteзастаріли. Було б допомогти оновити рядки, які посилаються на них, як: ActiveSupport::Dependencies.autoload_paths << path ActiveSupport::Dependencies.autoload_once_paths.delete(path)
Uzzar

8

Найкраще, що мені доводилося стикатися з тим, що я додав папку через відносний шлях при використанні Rspec. Я вважаю це достатньо багатослівним, але все ще приємним лайнером.

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))

1

Існує дорогоцінний камінь, який дозволить вам налаштувати шлях завантаження з більш приємним і чистим кодом. Перевірте це: https://github.com/nayyara-samuel/load-path .

Він також має хорошу документацію


-2

Я знаю, що давно це питання було задано давно, але я маю додаткову відповідь, якою хочу поділитися.

У мене є кілька додатків Ruby, які були розроблені іншим програмістом протягом декількох років, і вони повторно використовують однакові класи в різних програмах, хоча вони можуть отримати доступ до однієї бази даних. Оскільки це порушує правило СУХОГО, я вирішив створити бібліотеку класів, якою будуть користуватися всі додатки Ruby. Я міг би помістити його в основну бібліотеку Ruby, але це приховало б власний код у загальній кодовій базі, що я не хотів робити.

У мене була проблема, коли у мене виник конфлікт імен між уже визначеним іменем "profile.rb" та класом, яким я користувався. Цей конфлікт не був проблемою, поки я не спробував створити загальну бібліотеку коду. Зазвичай Ruby спочатку шукає місця розташування додатків, а потім переходить до розташувань $ LOAD_PATH.

Application_controller.rb не зміг знайти клас, який я створив, і видав помилку у вихідному визначенні, оскільки це не клас. Оскільки я видалив визначення класу з розділу програми / моделей програми, Ruby не зміг його знайти там і пішов шукати його в шляхи Ruby.

Отже, я змінив змінну $ LOAD_PATH, щоб включити шлях до каталогу бібліотеки, який я використовував. Це можна зробити у файлі environment.rb під час ініціалізації.

Навіть з додаванням нового каталогу до шляху пошуку, Ruby видавав помилку, оскільки переважно спочатку брав визначений системою файл. Шлях пошуку у змінній $ LOAD_PATH переважно здійснює пошук шляхів Ruby спочатку.

Отже, мені потрібно було змінити порядок пошуку так, щоб Рубі знайшла клас у моїй загальній бібліотеці, перш ніж шукати вбудовані бібліотеки.

Цей код зробив це у файлі environment.rb:

Rails::Initializer.run do |config|

* * * * *

path = []
path.concat($LOAD_PATH)
$LOAD_PATH.clear
$LOAD_PATH << 'C:\web\common\lib'
$LOAD_PATH << 'C:\web\common'
$LOAD_PATH.concat(path)

* * * * *

end

Я не думаю, що ви можете використовувати будь-які розширені конструкції кодування, подані раніше на цьому рівні, але це чудово працює, якщо ви хочете налаштувати щось під час ініціалізації у своєму додатку. Ви повинні підтримувати початковий порядок вихідної змінної $ LOAD_PATH, коли вона додається назад до нової змінної, інакше деякі основні класи Ruby втрачаються.

У файлі application_controller.rb я просто використовую файл

require 'profile'
require 'etc' #etc

і це завантажує користувацькі файли бібліотеки для всієї програми, тобто мені не потрібно використовувати команди require у кожному контролері.

Для мене це було рішення, яке я шукав, і я думав, що додам його до цієї відповіді, щоб передати інформацію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.