Как обезьяны исправить класс с помощью модуля?

У меня есть пара файлов. В одном я хотел бы расширить некоторые классы Ruby, например.

module Stylable
  class Array
    def styled
      "\n" << "*"*72 << self.to_s << "*"*72 << "\n"
    end
  end
end

В другом файле я определяю класс и смешиваю свой пользовательский модуль.

require './stylable'

class Printer
  include Stylable

  def initialize(object)
    @object = object
  end

  def print
    puts @object.styled
  end
end

Printer.new([1,2,3]).print

По какой-то причине я не могу использовать свой собственный метод Array#styled:

$ ruby printer.rb 
printer.rb:10:in `print': undefined method `styled' for [1, 2, 3]:Array (NoMethodError)
  from array_printer.rb:14:in `<main>'

Что я делаю не так?

Редактировать: решение от @MarekLipka ниже работает в Ruby 2+. Я должен сделать это на Ruby 1.9.3/Rails 3. Есть ли способ сделать это, или мне нужно использовать расширение глобального класса без оболочки модуля?


person sakovias    schedule 30.01.2015    source источник


Ответы (1)


Вам нужна такая функция, как уточнения. :

стильный.rb:

module Stylable
  refine Array do
    def styled
      "\n" << "*"*72 << self.to_s << "*"*72 << "\n"
    end
  end
end

принтер.rb:

require './stylable'
class Printer
  using Stylable
  # ...
end
Printer.new([1,2,3]).print

Преимущество использования уточнений в том, что этот мартык-патч работает только в рамках класса Printer, поэтому меньше шансов что-то сломать.

Причина, по которой ваш первоначальный подход не работает, заключается в том, что вместо обезьяньего исправления класса ::Array вы реализовали новый класс Stylable::Array (обратите внимание на пространство имен).

Если вы используете Ruby ‹ 2.0 и не хотите глобально исправлять Array обезьяны, вы можете создать собственный класс, который наследуется от массива:

class StylableArray < Array
  def styled
    "\n" << "*"*72 << self.to_s << "*"*72 << "\n"
  end
end

и используйте его в своем файле Printer:

Printer.new(StylableArray.new([1,2,3]))

Другой способ — глобальная Array установка исправлений обезьян, что не рекомендуется.

person Marek Lipka    schedule 30.01.2015
comment
Замечательно! К сожалению, мне приходится делать это в приложении Rails 3, использующем Ruby 1.9.3. Есть ли способ для этого, или мне нужно расширить класс глобально? - person sakovias; 30.01.2015
comment
Идеальный! Спасибо @Marek, я очень ценю ваш ответ! - person sakovias; 30.01.2015