Когда я должен использовать «объект класса», «модуль модуля», «модуль ядра» и ничего? - PullRequest
3 голосов
/ 21 марта 2011

Я новичок в метапрограммировании ruby ​​и вижу код метапрограммирования людей в разных местах, таких как class Object, class Module, module Kernel и "none" (т. Е. Вне блока определения класса / модуля).

Например: я создаю c_attr_accessor метод для доступа к переменным класса, и я не уверен, куда я должен поместить код, поскольку он работает в любом из этих случаев.

Как решить, в какое место более уместно поставить новый глобальный код?

Ответы [ 2 ]

3 голосов
/ 22 марта 2011

Каждый из этих примеров относится к разным случаям.

Если вы пишете методы, которые применяются ко всем объектам, то вы открываете класс Object, чтобы все объекты могли получить к нему доступ.Если вы пишете методы, применимые ко всем модулям, вы открываете Module.Всякий раз, когда вы открываете класс для добавления методов, методы должны применяться к всем экземплярам класса и ничему другому .

Расширение модуля Kernel отличается: люди делают это для добавления методовэто должно быть доступно для каждой области видимости, но не в качестве методов, вызываемых явным образом для объекта, делая их закрытыми.

Когда вы находитесь за пределами любого оператора class или module, вы находитесь вобласть действия объекта main и определяемые вами методы по умолчанию являются закрытыми методами Object.Это хорошо для небольших или простых программ, но вы в конечном итоге захотите использовать надлежащие модули в качестве пространств имен для организации ваших методов.

В качестве заключительного замечания по этому вопросу, вы всегда должны быть уверены, что вам действительно нужны методывы добавляете во встроенные классы и модули, чтобы они были доступны для всего в вашем приложении, включая внешние включения , потому что все они имеют общие встроенные модули.

Теперь, чтобы применить это, чтобы ответить на ваш вопрос,Поскольку вы определяете метод, который создает методы доступа для переменных класса, вы должны поместить его в класс Class, поскольку он применяется ко всем классам и ничего больше.Наконец, вы, скорее всего, будете использовать его только в определениях классов (в операторе class), поэтому мы должны сделать его закрытым:

class Class
  private

  def c_attr_accessor(name)
    # ...
  end
end

class User
  c_attr_accessor :class_variable_name

  # ...
end

Если он вам действительно не нужен в каждом классе (может быть, простонесколько), затем создайте «модуль mixin», чтобы расширить каждый класс, который нуждается в этой функции:

module ClassVariableAccessor
  private

  def c_attr_accessor(name)
    # ...
  end
end

class User
  extend ClassVariableAccessor

  c_attr_accessor :class_variable_name

  # ...
end

Обратите внимание, что вы используете Object#extend для добавления c_attr_accessor только к объекту User (помните, что классы являются объектами, вы много услышите об этом, если вы новичок в метапрограммировании Ruby).

Существует еще один способ реализации последнего примера, который работает путем явного расширения его базового класса через Module#included(base_class)«Метод ловушки» вызывается всякий раз, когда модуль включен, а базовый класс передается в base_class:

module ClassVariableAccessor
  def included(base_class)
    base_class.extend ClassMethods
  end

  module ClassMethods
    def c_attr_accessor(name)
      # ...
    end
  end
end

class User
  include ClassVariableAccessor

  c_attr_accessor :class_variable_name

  # ...
end

. Я рекомендую это последнее решение, потому что оно является наиболее общим и использует простой интерфейс, который не требуетсябыть обновленным.Надеюсь, это не так уж и много!

1 голос
/ 22 марта 2011

Вы пытались посмотреть, где определены нормальные атрибуты доступа? Я бы либо определил его в том же классе / модуле, либо создал бы свой собственный модуль, в котором будут использоваться все мои новые методы.

...