Переопределить метод внутри драгоценного камня из другого драгоценного камня - PullRequest
3 голосов
/ 05 января 2012

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

Метод, который я хочу переопределить: Sprockets :: Base.digest , чтобы при компиляции ресурсов приложения я мог основать отпечаток пальца на своей версии гема.

Как бы я поступил так?

В моем геме я создаю файл lib / sprockets / base.rb и помещаю следующий код:

class Sprockets::Base                                                                                                                                                                                                                                                           
  def digest
    @digest = digest_class.new.update(MyGem::VERSION)
    @digest.dup
  end
end

Когда я бегу bundle exec rake assets:precompile, я получаю:

undefined method 'logger=' for #<Sprockets::Environment:0x1315b040>

Так что мне почти кажется, что весь класс каким-то образом переопределяется (это теряет и другие методы), а не просто переопределяет один метод.

Если я включу этот фрагмент кода прямо в rakefile приложения, в котором используются оба гема, все будет отлично.

Ответы [ 2 ]

6 голосов
/ 05 января 2012

Невозможно переопределить весь класс Ruby таким образом, но я думаю, что возможно , чтобы предотвратить загрузку исходного класса ... если он использует автозагрузку. Мне было любопытно, поэтому я проверил https://github.com/sstephenson/sprockets/blob/master/lib/sprockets.rb, и да, Sprockets использует автозагрузку.

autoload :Base, "sprockets/base"

Важно, что не не загружает код. Он просто сообщает Ruby, что если / когда когда-либо встречается неопределенная константа, называемая «Sprockets :: Base», загрузить ее из указанного файла. Ваш патч определяет Sprockets :: Base до того, как он когда-либо вызывался, тем самым предотвращая загрузку исходного файла.

Когда вы перенесли ваш патч в Rakefile, что-то в Rails уже ссылалось на Sprockets :: Base, загружая оригинальный код. Затем ваш патч нанесен сверху.

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

Sprockets::Base
class Sprockets::Base
  def digest
...

Сначала ссылаясь на класс, вы должны заставить Ruby загрузить исходный класс. Тогда вы можете спокойно заняться переопределением одного из его методов.

1 голос
/ 06 января 2012

Хорошо, я пометил ваш ответ правильно, но это действительно привело меня к выяснению проблемы.

В любом случае, приложению rails требовался мой базовый файл вместо того, который был в самом геме.Что ты и сказал.Однако причина, по которой это произошло, кажется, была вызвана самим путем.Путь к файлу был в основном таким же, как и у гема (lib / sprockets / base.rb).

Перемещение этого файла в «пространство имен» моего гема (lib / my_gem вместо lib / sprockets) и его переименованиечтобы sprockets_base.rb исправил проблему!Странно, да?

Другими словами, попытка сохранить правильную структуру каталогов на самом деле, кажется, запутала Rails в мысли, что это сам камень или что-то в этом роде.

...