Столкновение имени файла в Ruby с `require` - PullRequest
3 голосов
/ 30 декабря 2011

Как правильно обращаться с исходными файлами ruby ​​с одинаковыми именами и обеспечить загрузку правильного файла данным оператором require?

Фон

Я хочу использовать гем ruby-geometry в моем приложении Rails 3.

Я пытаюсь использовать класс ruby-geometry Polygon:

require 'geometry'  # the main ruby-geometry gem file

module SomeModule
    def SomeMethod(vertices)
        polygon = Geometry::Polygon.new(vertices)

        # Do some stuff with polygon...
    end
end

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

NameError: uninitialized constant Geometry::Polygon

Это странно, потому что мне кажется, что я могу без проблем работать с любыми другими классами ruby-geometry (например, Geometry::Point, Geometry::Segment).

Проблема

Проблема в том, что мое приложение содержит исходный файл с именем polygon.rb (содержит модель ActiveRecord) и , так же как и гем ruby-geometry . Поэтому, когда гем ruby-geometry require имеет свой собственный polygon.rb, он заканчивает тем, что загружает polygon.rb моего приложения вместо этого. Предположительно, это все в том порядке, в котором рубин просматривает каталоги.

Каков «правильный» подход к разрешению этого конфликта имен?

Очевидно, в коде вы можете использовать модули, чтобы различать пространства имен для разрешения конфликтов имен классов. Есть ли простой способ различать исходные файлы с одинаковыми именами, когда require -ing их?

1 Ответ

1 голос
/ 30 декабря 2011

ИМХО, это ошибка в реализации гема geometry . Он полагается на переменную окружения $LOAD_PATH, чтобы решить, где его запрошенные файлы. Я бы предпочел использовать require_relative или значение File.dirname(__FILE__), чтобы в моих драгоценных камнях требовались файлы относительного пути.

Для решения вашей проблемы вы можете потребовать гем геометрии до того, как Rails добавляет свои собственные пути к переменной окружения $LOAD_PATH.

Один из способов сделать это, который мне помог, это явно потребовать этот драгоценный камень в GEMFILE:

gem "ruby-geometry", :require => "geometry"

Другим способом было бы удалить путь app/models из массива $LOAD_PATH, прежде чем потребовать geometry gem:

old_load_path = $LOAD_PATH
$LOAD_PATH.delete(File.expand_path("#{Rails.root}/app/models"))
require "geometry"
$LOAD_PATH.replace(old_load_path)

Но это безобразно, как ад.

...