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


167

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

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 
+5

Я только что видел эту статью обсуждали способы создания методов частного класса и думал, что это было хорошо: http://jakeyesbeck.com/2016/01/24/ruby- приват-класс-метода /?utm_source = rubyweekly & utm_medium = email 28 янв. 162016-01-28 22:07:26

206

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 

В качестве альтернативы (в рубин 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 

39

По умолчанию все методы класса являются общедоступными. Для того, чтобы сделать их частными вы можете использовать Module#private_class_method как @tjwallace написал или определить их по-разному, как вы делали это:

class << self 

    private 

    def method_name 
    ... 
    end 
end 

class << self открывает одноэлементный класс SELF, так что методы могут быть переопределена для текущего объекта самостоятельно. Это используется для определения метода class/module ("static"). Только там, определяя частные методы, действительно дает вам методы частного класса.


94

ExiRe писал:

Такое поведение рубин действительно расстраивает. Я имею в виду, если вы переместите в приватный раздел self.method, тогда он НЕ является частным. Но если вы перемещаете его в класс < <, то он внезапно срабатывает. Это просто отвратительно.

Сбивать с толку, возможно, это расстраивает, возможно, это будет, но отвратительно это определенно не так.

Это имеет смысл, как только вы поймете объектную модель Руби и соответствующая method lookup flow, особенно принимая во внимание, что private является НЕ модификатор доступа/видимость, но на самом деле вызов метода (с классом в качестве его получателя), как обсуждалось here ... нет такой вещи, как «частный раздел» в Ruby.

Для определения частных экземпляра методы, вы называете private на классе экземпляра, чтобы установить видимость по умолчанию впоследствии определенные методы к частному ... и, следовательно, имеет смысл определить частную класс методы по телефону private на класс класса, т. е. класс. его метакласса.

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

  0

Итак, если я правильно понимаю, у Ruby нет ключевых слов-модификаторов доступа (public, private и protected), а есть методы модификатора доступа (public, private, protected)? Это что-то, что должно быть поднято на рубиновом контролере ошибок для Matz для реализации правильных модификаторов доступа к ключевому слову или это ожидаемое поведение? 21 мар. 132013-03-21 16:00:03

+10

@Edward Это _designed_ таким образом http://junichiito.blogspot.co.uk/2012/03/matz-answers-why-ruby-lets-sub-classes.html. Почему «правильно»? 03 апр. 132013-04-03 11:58:26

+1

Следуя этому, вместо того, чтобы делать 'private_class_method: method_name', вы можете сделать' private_class_method def method_name ... '. 08 дек. 142014-12-08 23:32:08

  0

'send (private_method)' также доступен вне объекта. 23 июн. 152015-06-23 20:24:00

+1

@ bjt38 Просто для ясности это будет 'private_class_method def self.method_name' 15 фев. 162016-02-15 09:52:14


4

Я тоже, найду Рубин (или, по крайней мере, об этом знаю), за исключением отметки в этой области.Например следующее делает то, что я хочу, но неуклюж,

class Frob 
    attr_reader :val1, :val2 

    Tolerance = 2 * Float::EPSILON 

    def initialize(val1, val2) 
     @val2 = val1 
     @val2 = val2 
     ... 
    end 

    # Stuff that's 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-синтаксис и мои метрики качества кода сговорились сделал для громоздкого кода. Чтобы код работал так, как я хочу, и чтобы успокоить метрики, я должен сделать метод сравнения(). Поскольку я не хочу, чтобы он был частью общедоступного API класса, мне нужно, чтобы он был приватным, но «частный» на сам по себе не работает. Вместо этого я могу использовать «private_class_method» или некоторые подобные обходы. Это, в свою очередь, заставляет использовать «self.class.send (: сравнение ...». Для каждой переменной я проверить в «==()» Теперь немного громоздким

  0

Тот факт, что вам нужно использовать __send__, не имеет никакого отношения к тому, как вы« помечаете »методы класса private. Частные методы нельзя вызывать из «снаружи». 22 апр. 152015-04-22 08:01:35


9

Только для. полнота, мы можем также избежать объявления private_class_method в отдельной строке. Я лично не нравится это использование, но хорошо знать, что она существует.

private_class_method def self.method_name 
.... 
end 

1

методы экземпляра определяются внутри блока определения класса. методы класса определяются как одноэлементные методы для одноэлементного класса класса, также неофициально называемые «метаклассом» или «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 

Получатель «сообщений приватных» - себя - внутри class A является class object A. self внутри блока class << A - это еще один объект, класс singleton.

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

class A 
    # self is A and private call "A.private()" 
    private def instance_method; end 

    class << self 
    # self is A's 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 

Вы можете увидеть ошибку [что Руби разработчики языка] сделали? Вы переключитесь на частный доступ для всех будущих методов экземпляра A, но приступайте к объявлению метода singleton для другого класса - Singleton.


-5

Как рубин 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 
  0

Я пробовал это с помощью 'private def self.second_method' перед каждым нотом метода, который не работал на моем ruby ​​2.3.3. Но эта нотация работает для меня. 03 июн. 172017-06-03 15:44:40

+9

Это неверно, так как вызов 'Check.second_method' также будет работать без проблем, поэтому он не является частным. 25 июл. 172017-07-25 08:49:56