#ruby #module
#ruby #модуль
Вопрос:
Какой предпочтительный метод добавления функциональности модуля в код ruby библиотеки?
Рассмотрим следующее:
module MyExceptions
class SomethingBadHappenedTheLibarayDesignerDidntConsider < StandardError; end
end
Как я могу добавить MyExceptions
модуль в класс, который я не контролирую?
Обновление, в my_library_class_exceptions.rb
котором я сделал:
class LibraryClass
include MyExceptions
end
module MyExceptions
class SomethingBadHappenedTheLibarayDesignerDidntConsider < StandardError; end
end
Но консоль возвращает: NameError: uninitialized constant LibraryClass::MyExceptions
Комментарии:
1. Вам нужно убедиться, что ваши файлы названы правильно, чтобы автозагрузка работала.
MyExceptions
должно быть в «my_exceptions.rb». Куда вы поместили этот файл?2. вызывается класс библиотеки, который я хочу переопределить
Samurai
, поэтому я помещаю весь код, указанный в моем обновлении, в пустой файл с именем:app/models/samurai.rb
3. Этот файл не будет загружен автоматически. Когда вы ссылаетесь
MyExceptions
MyExceptions
на и не является известной константой, запускается автоматическая загрузкаmy_exceptions.rb
и выполняется поиск имени файла. Вам придется либо включить файл вручную, либо назвать его в соответствии с его содержимым.
Ответ №1:
В Ruby вы можете открыть определение любого класса позже и изменить его.
Ниже приведен надуманный пример переопределения разделения для использования пользовательского исключения путем повторного открытия ранее созданного класса.
class Foo
def divide(a, b)
a/b
end
end
foo = Foo.new()
foo.divide(1, 0)
module MyExceptions
class MyDivisionError < StandardError; end
end
class Foo
include MyExceptions
alias old_divide divide
def divide(a, b)
old_divide(a, b)
rescue ZeroDivisionError
raise MyDivisionError
end
end
foo.divide(1, 0)
Ответ №2:
Глядя на ваше обновление, простая причина, по которой оно не работает, заключается в следующем: вы используете MyExceptions до его определения. Исправленная версия вашего файла — повторное открытие библиотечного класса:
require 'thelib'
module MyExceptions
class SomethingBadHappenedTheLibarayDesignerDidntConsider < StandardError; end
end
LibraryClass.class_eval do
include MyExceptions
end
Этот трюк с оценкой класса, возможно, является более безопасным способом повторного открытия class, чем просто class LibraryClass
снова: он предупредит вас, если вы пропустили classname.
Кстати: я не совсем понимаю, как вы планируете использовать MyException тогда.. вероятно, это означало бы еще несколько исправлений и / или перенос частей библиотеки.
ОБНОВЛЕНИЕ: вышеизложенное предполагает, что у вас есть thelib.rb
в том же каталоге, по крайней мере, со следующим содержимым:
class LibraryClass
end
Комментарии:
1. Я реорганизовал по вашему предложению, все равно получая то же
NameError
самое.2. странно. Я обновил ответ, убедившись, что мы находимся на одной странице. Пожалуйста, проверьте еще раз.
Ответ №3:
Я получил эту работу, исправив несколько вещей и изменив несколько вещей.
-
Оказывается
LibraryClass
, на самом деле это был не класс, а модуль. Итак, я изменил:класс LibraryClass включает MyExceptions end
в в:
module LibraryClass
module MyExceptions
class SomethingBadHappenedTheLibarayDesignerDidntConsider < StandardError; end
end
end
- Затем я
library_class.rb
перешелliblibrary_class_extensions.rb
и убедился, чтоlib
это часть пути автозагрузки. - Затем в инициализаторе я вызвал
require 'library_class_extensions'
Я думаю, что это лучший шаблон для поведения, которого я все равно пытался достичь, поскольку это действительно больше похоже на код библиотечного типа, который app/model
вводит код.
Я голосую за ответы, данные всеми, за их героические усилия.