Я новичок в Ruby (опыт работы с Python, С++ и C). Мне нужно создать класс, который должен использоваться только другими классами и методами в модуле. В Python я бы просто назвал это __classname. Я бы использовал пустой typedef в С++. Как это сделать в Ruby (или я лаяю неправильное дерево и не делаю это "Ruby way"?)
Частный класс (не классный метод) в модуле Ruby?
Ответ 1
Я пока не видел такой концепции в Ruby, но я думаю, вы могли бы имитировать это, создав частный метод, который вернет класс, созданный как локальная переменная (помните, что в Ruby класс - это объект, как любой другой, и может быть экземпляр в методе и возвращен им).
Кстати, даже частные методы в Ruby не такие частные, как на других языках - вы всегда можете получить к ним доступ с помощью метода send
. Но это означает, что вы знаете, что делаете.
Ответ 2
Самое главное понять, что класс не является чем-то особенным. Это просто объект. По соглашению классы назначаются константам, но нет ничего, что говорит о том, что они должны быть.
И поскольку классы - это просто объекты, подобные любому другому объекту, вы делаете их частными так же, как и любой другой объект.
Вот возможности, о которых я могу думать, в порядке возрастания приватности:
- Просто вставьте их в пространство имен (т.е. модуль). В Ruby обычно предполагается, что все библиотечные модули и классы живут внутри пространства имен с тем же именем, что и библиотека (т.е.
my_awesome_library
→MyAwesomeLibrary
), но в целом все, что вложено ниже этого пространства имен, считается приватным. На самом деле, помимо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