Частный класс (не метод класса) в модуле Ruby? - PullRequest
16 голосов
/ 16 августа 2010

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

Ответы [ 3 ]

27 голосов
/ 17 августа 2010

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

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

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

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

Ex:.

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 «Мы все взрослые по обоюдному согласию».

10 голосов
/ 25 февраля 2016

Взяв эту информацию прямо из этого сообщения в блоге , но начиная с 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
4 голосов
/ 16 августа 2010

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

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

...