Как я могу получить константы, определенные в классе модуля Ruby через отражение? - PullRequest
40 голосов
/ 22 февраля 2010

Я пытался заполучить главу метапрограммирования "Ruby Programming Language" Матца и Фланагана, однако я не мог понять вывод следующего фрагмента кода, который я придумал:

p Module.constants.length           # => 88
$snapshot1 = Module.constants       
class A
  NAME=:abc

  $snapshot2 = Module.constants
  p $snapshot2.length               # => 90
  p $snapshot2 - $snapshot1         # => ["A", "NAME"]

end
p Module.constants.length           # => 89
p Module.constants - $snapshot1     # => ["A"]
p A.constants                       # => ["NAME"]

В книге говорится, что метод класса constants возвращает список констант для класса (как вы можете видеть в выводе для A.constants). Я пытался получить список констант, определенных для класса Module, когда натолкнулся на странное поведение, описанное выше.

Константы

A отображаются в Module.constants. Как получить список констант, определенных классом Module?

Состояние документы

Module.constants возвращает все константы, определенные в системе. включая имена всех классов и методов

Поскольку A наследует свою реализацию от Module.constants, как он ведет себя по-разному в базовом и производном типах?

p A.class               # => Class
p A.class.ancestors       # => [Class, Module, Object, Kernel]

Примечание. Если вы используете Ruby 1.9, constants вернет массив символов вместо строк.

Ответы [ 2 ]

53 голосов
/ 22 февраля 2010

Хороший вопрос!

Ваша путаница связана с тем, что метод класса Module.constants скрывает метод экземпляра Module#constants для Module.

В Ruby 1.9 это было решено добавлением необязательного параметра:

# No argument: same class method as in 1.8:
Module.constants         # ==> All constants
# One argument: uses the instance method:
Module.constants(true)   # ==> Constants of Module (and included modules)
Module.constants(false)  # ==> Constants of Module (only).

В приведенном выше примере A.constants вызывает Module#constants (метод экземпляра), а Module.constants вызывает, Module.constants.

В Ruby 1.9 вы хотите вызвать Module.constants(true).

В Ruby 1.8 можно вызывать метод экземпляра #constants для Module. Вам нужно получить метод экземпляра и связать его как метод класса (используя другое имя):

class << Module
  define_method :constants_of_module, Module.instance_method(:constants)
end

# Now use this new class method:
class Module
   COOL = 42
end
Module.constants.include?("COOL")  # ==> false, as you mention
Module.constants_of_module         # ==> ["COOL"], the result you want

Хотелось бы полностью перенести функциональность 1.9 на 1.8 для моего backports гема, но я не могу придумать, как получить в Ruby 1.8 только константы модуля, исключая унаследованные.

Редактировать : Просто изменили официальную документацию, чтобы правильно отразить это ...

3 голосов
/ 02 марта 2010

Мне пришлось на некоторое время вернуться в свою мыслящую пещеру после ответа Марка. Повозился с большим количеством фрагментов кода, а затем еще немного. Наконец, когда разрешение метода Ruby, казалось, имело смысл, записало это как пост в блоге, чтобы я не забыл.

Обозначение: если A " является собственным классом A

Когда вызывается A.constants, разрешение метода (см. Изображение в моем блоге для получения наглядного пособия) ищет следующие места в порядке

  • MyClass", Object", BasicObject" (одноэлементные методы)
  • Class (методы экземпляра)
  • Module (методы экземпляра)
  • Object (методы экземпляра) и ядро ​​
  • BasicObject (методы экземпляра)

Ruby находит метод экземпляра Module#constants

Когда вызывается Module.constants, Руби смотрит на

  • Module", Object", BasicObject" (одноэлементные методы)
  • Class (методы экземпляра)
  • Module (методы экземпляра)
  • Object (методы экземпляра) и ядро ​​
  • BasicObject (методы экземпляра)

на этот раз Руби находит метод singleton / class в Module".constants, как сказал Марк.

Модуль определяет одноэлементный метод, который скрывает метод экземпляра. Метод singleton возвращает все известные константы, а метод экземпляра возвращает константы, определенные в текущем классе и его предках.

...