Базовое метапрограммирование: расширение существующего класса с помощью модуля? - PullRequest
8 голосов
/ 30 августа 2011

Я бы хотел, чтобы часть моего модуля расширила класс String.

Это не работает

module MyModule
  class String
    def exclaim
      self << "!!!!!"
    end
  end
end

include MyModule

string = "this is a string"
string.exclaim

#=> NoMethodError 

Но это так

module MyModule
  def exclaim
    self << "!!!!!"
  end
end

class String
  include MyModule
end

string = "this is a string"
string.exclaim

#=> "this is a string!!!!!"

Я не хочу, чтобы все остальные функции MyModule были сброшены в String. Включение его снова на самом высоком уровне кажется уродливым. Конечно, есть более аккуратный способ сделать это?

Ответы [ 2 ]

26 голосов
/ 30 августа 2011

Метод exclaim в вашем первом примере определяется внутри класса с именем MyModule::String, который не имеет ничего общего со стандартным классом String.

Внутри вашего модуля вы можете открыть стандартный класс String (в глобальном пространстве имен) следующим образом:

module MyModule
  class ::String
    # ‘Multiple exclamation marks,’ he went on, shaking his head,
    # ‘are a sure sign of a diseased mind.’ — Terry Pratchett, “Eric”
    def exclaim
      self << "!!!!"
    end
  end
end
1 голос
/ 30 августа 2011

Я не уверен, что понял ваш вопрос, но почему бы не открыть строку в файле, скажем exclaim.rb, а затем потребовать ее, когда вам это нужно:

exclaim.rb

  class String
    def exclaim
      self << "!!!!!"
    end
  end

, а затем

require "exclaim"

"hello".exclaim

Но, может быть, я что-то упустил?

...