Предпочтительный метод Ruby для добавления модулей в код библиотеки?

#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:

Я получил эту работу, исправив несколько вещей и изменив несколько вещей.

  1. Оказывается LibraryClass , на самом деле это был не класс, а модуль. Итак, я изменил:

    класс LibraryClass включает MyExceptions end

в в:

 module LibraryClass
    module MyExceptions
        class SomethingBadHappenedTheLibarayDesignerDidntConsider < StandardError; end
    end
end
  
  1. Затем я library_class.rb перешел liblibrary_class_extensions.rb и убедился, что lib это часть пути автозагрузки.
  2. Затем в инициализаторе я вызвал require 'library_class_extensions'

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

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