Как создать метод частного класса?

Как работает этот метод создания метода частного класса:

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