Наследовать новый метод класса во время выполнения - PullRequest
2 голосов
/ 01 февраля 2012

В Ruby <ClassName>.constants полезен для проверки классов:

> Numeric.constants(false)
=> [:KILOBYTE, :MEGABYTE, :GIGABYTE, :TERABYTE, :PETABYTE, :EXABYTE]
> Object.constants(false)
=> [:Object, :Module, ...]

Это определено в Module:

> Object.method(:constants)
=> #<Method: Class(Module)#constants>

Я хотел бы добавить другой метод для печати хэша со всеми константами и их значениями. Вот результат на данный момент:

def Module.constants_hash(inherit=true)
    self.constants(inherit).inject({}) do |hash, constant|
        hash[constant] = self::const_get(constant)
        hash
    end
end

Это работает для Module (хотя оно не имеет констант, поэтому результатом является просто пустой хеш), но оно не наследуется :

> Object.constants_hash(false)
NoMethodError: undefined method `constants_hash' for Object:Class
from (pry):117:in `<main>'

Конечно, я могу изменить имя класса в коде, например. Object для выполнения вызова, но возможно ли заставить все зависимые модули наследовать новый метод ? Другими словами, возможно ли добавить метод во время выполнения , который затем наследуется классами, которые require модифицируют класс?

Я бы не стал перегружать исходный Module.constants, чтобы избежать изменения API.

Ответы [ 2 ]

4 голосов
/ 01 февраля 2012

Object является экземпляром типа Class. Class класс наследуется от Module. Чтобы Object.constants_hash работал, вам нужно определить экземпляр метод Class или Module классов:

class Module
  def constants_hash(inherit=true)
      self.constants(inherit).inject({}) do |hash, constant|
          hash[constant] = self::const_get(constant)
          hash
      end
  end
end

В своем коде вы просто добавляете constants_hash к одноэлементному классу из Module экземпляра (типа Class), поэтому вы не получите ожидаемый результат.

0 голосов
/ 01 февраля 2012

Возможно, вам повезет больше, если объявить этот метод в модуле, а затем смешать его с каждым контекстом, как требуется:

module ConstantsHash
  def constants_hash(inherit = true)
    Hash[
      self.constants(inherit).collect do |constant|
        [ constant, const_get(constant) ]
      end
    ]
  end
end

Module.extend(ConstantsHash)
Object.extend(ConstantsHash)

puts Object.constants_hash.inspect

Как примечание, использование Hash[] вместо inject({ }), кажется, работает лучше в подобных случаях.

...