Как создать метод частного класса?
Как работает этот метод создания метода частного класса:
class Person
def self.get_name
persons_name
end
class << self
private
def persons_name
"Sam"
end
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"
Но это не так:
class Person
def self.get_name
persons_name
end
private
def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Ответы
Ответ 1
private
не работает, если вы определяете метод на явном объекте (в вашем случае self
). Вы можете использовать private_class_method
, чтобы определить методы класса как частные (или, как вы описали).
class Person
def self.get_name
persons_name
end
def self.persons_name
"Sam"
end
private_class_method :persons_name
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Альтернативно (в ruby 2.1+), поскольку определение метода возвращает символ имени метода, вы также можете использовать его следующим образом:
class Person
def self.get_name
persons_name
end
private_class_method def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
Ответ 2
ExiRe написал:
Такое поведение рубина действительно расстраивает. Я имею в виду, если вы переедете в частную секцию self.method, тогда она НЕ секретна. Но если вы перемещаете его в класс < я тогда внезапно работает. Это просто отвратительно.
Сбивать с толку это, вероятно, расстраивает, возможно, это так, но отвратительно это определенно не так.
Это имеет смысл, если вы поймете объектную модель Ruby и соответствующий поток поиска "noreferrer > , особенно если учесть, что private
есть НЕ модификатор доступа/видимости, но на самом деле вызов метода (с классом в качестве получателя), как обсуждалось здесь... нет такой вещи как" частный раздел" в Ruby.
Чтобы определить частные методы экземпляра, вы вызываете private
в классе экземпляра, чтобы установить видимость по умолчанию для впоследствии определенных методов для частного... и, следовательно, имеет смысл определить частный class, вызвав private
в классе класса, т.е. его метакласс.
Другие основные, самопровозглашенные языки OO могут дать вам менее сложный синтаксис, но вы определенно торгуете этим против непонятной и менее последовательной (непоследовательной?) объектной модели без возможности использования метапрограммирования Ruby.
Ответ 3
По умолчанию все методы класса являются общедоступными. Чтобы сделать их частными, вы можете использовать Module # private_class_method, например @tjwallace, или определить их по-другому, как и вы:
class << self
private
def method_name
...
end
end
class << self
открывает класс self singleton, поэтому методы могут быть переопределены для текущего объекта self. Это используется для определения метода class/module ( "static" ). Только там, определяя частные методы, действительно дает вам частные методы класса.
Ответ 4
Только для полноты мы также можем избежать объявления private_class_method в отдельной строке. Я лично не люблю это использование, но хорошо знаю, что он существует.
private_class_method def self.method_name
....
end
Ответ 5
Я тоже, найдите Ruby (или, по крайней мере, мое знание об этом), за исключением метки
в этой области. Например, следующее делает то, что я хочу, но неуклюже,
class Frob
attr_reader :val1, :val2
Tolerance = 2 * Float::EPSILON
def initialize(val1, val2)
@val2 = val1
@val2 = val2
...
end
# Stuff that likely to change and I don't want part
# of a public API. Furthermore, the method is operating
# solely upon 'reference' and 'under_test' and will be flagged as having
# low cohesion by quality metrics unless made a class method.
def self.compare(reference, under_test)
# special floating point comparison
(reference - under_test).abs <= Tolerance
end
private_class_method :compare
def ==(arg)
self.class.send(:compare, val1, arg.val1) &&
self.class.send(:compare, val2, arg.val2) &&
...
end
end
Мои проблемы с вышеприведенным кодом заключаются в том, что требования синтаксиса Ruby
и мои показатели качества кода сговорились сделать для громоздкого кода.
Чтобы код работал так, как я хочу, и чтобы успокоить показатели, я должен
make compare() метод класса. Поскольку я не хочу, чтобы это было частью
публичный API класса, мне нужно, чтобы он был закрытым, но 'private' by
сам не работает. Вместо этого я могу использовать 'private_class_method'
или некоторые такие работы. Это, в свою очередь, заставляет использовать
'self.class.send(: compare...' для каждой переменной, которую я тестирую в '==()'.
Теперь это немного громоздко.
Ответ 6
Методы экземпляров определяются внутри блока определения класса. Методы класса определяются как одноэлементные методы для одноэлементного класса класса, также неофициально называемые "метаклассом" или "eigenclass". private
не является ключевым словом, а метод (Module # private).
Это вызов метода self#private
/A#private
, который "переключает" частный доступ для всех будущих методов метода экземпляра, пока не переключится иначе:
class A
private
def instance_method_1; end
def instance_method_2; end
# .. and so forth
end
Как отмечалось ранее, методы класса - это, по сути, одноточечные методы, определенные в одноэлементном классе.
def A.class_method; end
Или используя специальный синтаксис, чтобы открыть тело определения анонимного, одноэлементного класса A:
class << A
def class_method; end
end
Получателем "message private" - self-inside class A
является объект класса A. self внутри блока class << A
- это другой объект, singleton-класс.
В следующем примере на самом деле вызывается два разных метода, называемых private, с использованием двух разных получателей или целей для вызова. В первой части мы определяем метод частного экземпляра ( "на класс А" ), в последнем мы определяем метод частного класса (на самом деле это одноэлементный метод для одноэлементного объекта класса A).
class A
# self is A and private call "A.private()"
private def instance_method; end
class << self
# self is A singleton class and private call "A.singleton_class.private()"
private def class_method; end
end
end
Теперь немного перепишите этот пример:
class A
private
def self.class_method; end
end
Вы видите ошибку [дизайнеры языка Ruby]? Вы переключаетесь на частный доступ для всех будущих методов экземпляра A, но приступайте к объявлению метода singleton для другого класса, singleton class.
Ответ 7
По состоянию на рубин 2.3.0
class Check
def self.first_method
second_method
end
private
def self.second_method
puts "well I executed"
end
end
Check.first_method
#=> well I executed