Добавление каталога в $ LOAD_PATH (Ruby) - PullRequest
88 голосов
/ 08 мая 2009

Я видел два часто используемых метода добавления каталога исполняемого файла в $ 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__)

Есть какая-то причина, чтобы пойти с одним на другого?

Ответы [ 7 ]

144 голосов
/ 22 сентября 2009

Путь загрузки Ruby очень часто пишется как $:, но только потому, что он короткий, он не делает его лучше. Если вы предпочитаете ясность, а не хитрость, или если краткость ради самого себя заставляет вас зудеть, вам не нужно делать это только потому, что все остальные так и делают. Передай привет ...

$LOAD_PATH

... и попрощаться с ...

# I don't quite understand what this is doing...
$:
49 голосов
/ 08 мая 2009

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

22 голосов
/ 11 июля 2009

Я не слишком люблю "быстрый и грязный" способ. Любой новичок в Ruby будет размышлять, что такое $:..

Я считаю это более очевидным.

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__)))

Я видел его во множестве разных проектов ruby ​​во время просмотра GitHub.

Кажется, это конвенция?

8 голосов
/ 06 декабря 2009

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

Недостаток выполнения этого быстрого и грязного способа, как вы упомянули, заключается в следующем: если у вас уже есть каталог в вашем загрузочном пути, он повторится.

Пример:

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

/---vendor
  |
  |---/plugins
        |
        |---/todo
              |
              |---/lib
                    |
                    |---/app
                          |
                          |---/models
                          |---/controllers
              |
              |---/rails
                    |
                    |---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 

Обратите внимание, как я говорю блоку кода выполнять действия внутри блока со строками 'models', 'controller' и 'models', где я повторяю 'models'. (К вашему сведению, %w{ ... } - это просто еще один способ сказать Ruby, что он должен содержать массив строк). Когда я запускаю 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, вы, вероятно, очень хорошо представляете себе, что вы делаете, и, вероятно, не ошибетесь, повторяя пути. Если вы новичок, я бы пошел более длинным путем, пока вы действительно не поймете, что делаете.

6 голосов
/ 05 ноября 2015

Лучше всего я сталкивался за добавление директории по относительному пути при использовании Rspec. Я нахожу это достаточно многословным, но все же хороший лайнер.

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
1 голос
/ 26 сентября 2013

Существует драгоценный камень, который позволит вам настроить путь загрузки с более приятным и чистым кодом. Проверьте это: https://github.com/nayyara-samuel/load-path.

Он также имеет хорошую документацию

0 голосов
/ 24 октября 2018

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

У меня есть несколько приложений на Ruby, которые были разработаны другим программистом в течение нескольких лет, и они повторно используют одни и те же классы в разных приложениях, хотя могут иметь доступ к одной и той же базе данных. Поскольку это нарушает правило DRY, я решил создать библиотеку классов, которая будет использоваться всеми приложениями Ruby. Я мог бы поместить его в основную библиотеку Ruby, но это скрыло бы пользовательский код в общей кодовой базе, чего я не хотел делать.

У меня была проблема, когда у меня был конфликт имен между уже определенным именем "profile.rb" и классом, который я использовал. Этот конфликт не был проблемой, пока я не попытался создать общую библиотеку кода. Обычно Ruby сначала ищет местоположения приложений, а затем переходит в местоположения $ LOAD_PATH.

application_controller.rb не смог найти класс, который я создал, и выдал ошибку в исходном определении, потому что это не класс. Поскольку я удалил определение класса из раздела app / models приложения, Ruby не смог найти его там и начал искать его в путях Ruby.

Итак, я изменил переменную $ LOAD_PATH, чтобы включить путь к каталогу библиотеки, который я использовал. Это можно сделать в файле environment.rb во время инициализации.

Даже с новым каталогом, добавленным в путь поиска, Ruby выдавал ошибку, потому что он в первую очередь брал файл, определенный системой. Путь поиска в переменной $ LOAD_PATH преимущественно ищет пути Ruby.

Итак, мне нужно было изменить порядок поиска, чтобы 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 в каждом контроллере.

Для меня это было решение, которое я искал, и я подумал, что добавлю его в этот ответ, чтобы передать информацию.

...