Подтвердить что ты не робот

Частный класс (не классный метод) в модуле Ruby?

Я новичок в Ruby (опыт работы с Python, С++ и C). Мне нужно создать класс, который должен использоваться только другими классами и методами в модуле. В Python я бы просто назвал это __classname. Я бы использовал пустой typedef в С++. Как это сделать в Ruby (или я лаяю неправильное дерево и не делаю это "Ruby way"?)

4b9b3361

Ответ 1

Я пока не видел такой концепции в Ruby, но я думаю, вы могли бы имитировать это, создав частный метод, который вернет класс, созданный как локальная переменная (помните, что в Ruby класс - это объект, как любой другой, и может быть экземпляр в методе и возвращен им).

Кстати, даже частные методы в Ruby не такие частные, как на других языках - вы всегда можете получить к ним доступ с помощью метода send. Но это означает, что вы знаете, что делаете.

Ответ 2

Самое главное понять, что класс не является чем-то особенным. Это просто объект. По соглашению классы назначаются константам, но нет ничего, что говорит о том, что они должны быть.

И поскольку классы - это просто объекты, подобные любому другому объекту, вы делаете их частными так же, как и любой другой объект.

Вот возможности, о которых я могу думать, в порядке возрастания приватности:

  • Просто вставьте их в пространство имен (т.е. модуль). В Ruby обычно предполагается, что все библиотечные модули и классы живут внутри пространства имен с тем же именем, что и библиотека (т.е. my_awesome_libraryMyAwesomeLibrary), но в целом все, что вложено ниже этого пространства имен, считается приватным. На самом деле, помимо Test::Unit::TestCase, я не могу представить ни одного примера трехуровневого пространства имен, которое, как предполагается, будет использоваться клиентским кодом.
  • то же, что и 1., но назовите его чем-то очевидным, например MyAwesomeLibrary::Internal::FfiStruct
  • то же, что и 1. или 2. и пометьте его тегом :nodoc: RDoc.
  • похож на 3., но используйте более современную систему документации, такую ​​как YARD, которая фактически позволяет явно разделить частные API.
  • Используйте метод вместо константы. Методы могут быть сделаны частными. (Для обеспечения согласованности имя метода можно начинать с буквы верхнего регистра, чтобы он был похож на константу. Там ничего не мешает этому, соглашение snake_case - это просто: соглашение).
  • Используйте переменную экземпляра. Они всегда частные. Обратите внимание, что как частные методы, так и переменные экземпляра могут быть тривиально доступны с помощью отражения. send представляется более широко используемым, чем instance_variable_get, хотя, поэтому я считаю, что переменные экземпляра имеют более высокий уровень конфиденциальности, чем методы.
  • Действительно, единственный способ получить реальную конфиденциальность или инкапсуляцию - использовать локальные переменные и блокировки. Обратите внимание, что это может помешать вам использовать синтаксис определения модуля, класса или метода Ruby, поскольку они создают новые области действия. Во всех случаях, когда вам нужен доступ к классу, вам нужно использовать Module.new, Class.new или Module#define_method.

Пример:.

module MyAwesomeLibrary
  struct = Class.new(FFI::Struct) do
    # ...
  end

  PublicInterface = Class.new do
    define_method(:initialize) do |bar|
      @foo = struct.new(bar)
    end
  end
end

И да, это единственный способ добиться истинного 100% -ного скрытия информации и инкапсуляции в Ruby.

Однако обычным способом Ruby было бы просто документировать материал как частный (возможно, надавить его на уровень пространства имен) и доверять своим коллегам-разработчикам. В сообществе Ruby это иногда суммируется под лозунгом Python "Мы все соглашаем взрослых".

Ответ 3

Принимая эту информацию прямо из этого сообщения в блоге, но с Ruby 1.9.3 вы можете создать частный класс в модуле с помощью private_constant:

class Person
  class Secret
    def to_s
      "1234vW74X&"
    end
  end
  private_constant :Secret

  def show_secret
    Secret.new.to_s
  end
end