Como é que essa abordagem de criação de um método de classe privada funciona:
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)"
Mas isso não:
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
ruby
access-specifier
99 milhas
fonte
fonte
Respostas:
private
parece não funcionar se você estiver definindo um método em um objeto explícito (no seu casoself
). Você pode usarprivate_class_method
para definir métodos de classe como privados (ou como você descreveu).Como alternativa (no ruby 2.1+), como uma definição de método retorna um símbolo do nome do método, você também pode usá-lo da seguinte maneira:
fonte
ExiRe escreveu:
Confundir provavelmente é frustrante, mas pode ser nojento, mas definitivamente não é.
Faz todo o sentido quando você entende o modelo de objeto de Ruby e o fluxo de pesquisa do método correspondente , especialmente quando se considera que NÃO
private
é um modificador de acesso / visibilidade, mas na verdade uma chamada de método (com a classe como destinatária), conforme discutido aqui ... não existe uma seção particular no Ruby.Para definir métodos de instância privada , chame
private
a classe da instância para definir a visibilidade padrão para métodos subsequentemente definidos como private ... e, portanto, faz todo o sentido definir métodos de classe privada chamandoprivate
a classe da classe, ou seja. sua metaclasse.Outras linguagens OO auto-proclamadas tradicionais podem fornecer uma sintaxe menos confusa, mas você definitivamente troca isso contra um modelo de objeto confuso e menos consistente (inconsistente?) Sem o poder dos recursos de metaprogramação de Ruby.
fonte
private_class_method :method_name
você poderia fazerprivate_class_method def method_name...
.send(private_method)
também é acessível fora do objeto.private_class_method def self.method_name
Por padrão, todos os métodos de classe são públicos. Para torná-los privados, você pode usar o Módulo # private_class_method como @tjwallace escreveu ou defini-los de maneira diferente, como você fez:
class << self
abre a classe singleton do self, para que os métodos possam ser redefinidos para o atual objeto próprio. Isso é usado para definir o método de classe / módulo ("estático"). Somente lá, definir métodos privados realmente fornece métodos de classe privada.fonte
Apenas pela integridade, também podemos evitar a declaração de private_class_method em uma linha separada. Eu pessoalmente não gosto desse uso, mas é bom saber que ele existe.
fonte
Eu também acho Ruby (ou pelo menos o meu conhecimento disso) aquém da marca nesta área. Por exemplo, o seguinte faz o que eu quero, mas é desajeitado,
Meus problemas com o código acima é que os requisitos de sintaxe do Ruby e minhas métricas de qualidade de código conspiram para criar código complicado. Para que o código funcione como eu quero e silencie as métricas, devo fazer do compare () um método de classe. Como não quero que faça parte da API pública da classe ', preciso que ela seja privada, mas' privada 'por si só não funciona. Em vez disso, sou forçado a usar 'private_class_method' ou alguma solução alternativa. Por sua vez, isso força o uso de 'self.class.send (: compare ...' para cada variável que eu testo em '== ()'. Agora isso é um pouco complicado.
fonte
Os métodos de instância são definidos dentro de um bloco de definição de classe. Os métodos de classe são definidos como métodos singleton na classe singleton de uma classe, também conhecidos informalmente como "metaclasse" ou "autoclasse".
private
não é uma palavra-chave, mas um método ( Módulo # privado ).Esta é uma chamada ao método
self#private
/ naA#private
qual "alterna" o acesso privado para todas as próximas definições de método de instância até alternar de outra forma:Como observado anteriormente, os métodos de classe são realmente métodos singleton definidos na classe singleton.
Ou usando uma sintaxe especial para abrir o corpo da definição da classe anônima e singleton de A:
O receptor da "mensagem privada" - self -inside
class A
é o objeto de classe A. self dentro doclass << A
bloco é outro objeto, a classe singleton.O exemplo a seguir está na realidade chamando dois métodos diferentes chamados private , usando dois destinatários ou destinos diferentes para a chamada. Na primeira parte, definimos um método de instância privada ("na classe A"); na segunda, definimos um método de classe privada (na verdade, é um método singleton no objeto de classe singleton de A).
Agora, reescreva este exemplo um pouco:
Você consegue ver o erro [que os designers de linguagem Ruby] cometeram? Você ativa o acesso privado para todos os métodos de instância futuros de A, mas continua a declarar um método singleton em uma classe diferente, a classe singleton.
fonte
Ruby parece fornecer uma solução ruim. Para explicar, comece com um exemplo simples de C ++ que mostra o acesso a métodos de classe privada:
Executando o acima
Agora, Ruby não parece fornecer o equivalente. As regras de Ruby, eu acho, são que métodos privados não devem ser acessados com um receptor. Isso é,
Isso é bom para métodos de instância privada, mas causa problemas com métodos de classe privada.
Eu gostaria que Ruby funcionasse dessa maneira:
Mas, infelizmente, o acima exposto não funciona. Alguém sabe uma maneira melhor?
Quando vejo 'send' antes de um método, é um sinal claro de que o código está violando a intenção do designer da API, mas nesse caso o design é especificamente para que um método de instância da classe chame o método de classe privada.
fonte
A partir do ruby 2.3.0
fonte
private def self.second_method
antes de cada notação de método, que não estava funcionando no meu ruby 2.3.3. Mas essa notação funciona para mim.Check.second_method
também funcionaria sem problemas, por isso não é realmente particular.private_class_method :second_method