2010-05-20 5 views
32

Dans Ruby, comment créer une constante de classe privée? (i.e. qui est visible à l'intérieur de la classe, mais pas à l'extérieur)Comment faire des constantes de classe privée dans Ruby

class Person 
    SECRET='xxx' # How to make class private?? 

    def show_secret 
    puts "Secret: #{SECRET}" 
    end 
end 

Person.new.show_secret 
puts Person::SECRET # I'd like this to fail 
+1

Bien sûr, « privé » en Ruby ne veut pas dire ce que cela signifie dans la plupart des langues . Ruby n'est pas si grand que ça, alors si vous voulez accéder à quelque chose, vous pouvez toujours le faire (mais peut-être pas avec la syntaxe la plus évidente). Le 'private' de Ruby dit seulement qu'il ne peut pas être précédé d'un point (' .') (ce qui je suppose est aussi un indice pourquoi ça ne marchera pas sur '::') – Amadan

+2

Juste au cas où. Ruby 1.9.3 a maintenant des constantes privées. – whitequark

Répondre

12

Vous pouvez également modifier votre constante en une méthode de classe:

def self.secret 
    'xxx' 
end 

private_class_method :secret 

Ceci le rend accessible dans toutes les instances de la classe, mais pas à l'extérieur.

+0

Peut-être qu'un peu de méta-programmation rendrait cela plus acceptable. – DMisener

+0

J'y ai réfléchi un peu plus longtemps et j'ai ensuite réalisé que l'approche ci-dessus ne rend pas la constante disponible pour les méthodes d'instance, donc je pense que je m'en tiendrai à l'approche @@ var. – DMisener

+0

@DMisener: Ruby a une méthode pour les constantes manquantes, si quelqu'un veut de la magie de méta-programmation. –

9

Au lieu d'une constante, vous pouvez utiliser un @@ class_variable, qui est toujours privé.

class Person 
    @@secret='xxx' # How to make class private?? 

    def show_secret 
    puts "Secret: #{@@secret}" 
    end 
end 
Person.new.show_secret 
puts Person::@@secret 
# doesn't work 
puts Person.class_variable_get(:@@secret) 
# This does work, but there's always a way to circumvent privateness in ruby 

Bien sûr, puis Ruby fera rien pour faire respecter la @@ de secret de transmission permanente, mais Ruby fait très peu à appliquer pour commencer transmission permanente, alors ...

+0

Merci ... Cela semble évident avec le recul. – DMisener

1

Eh bien ...

@@secret = 'xxx'.freeze 

genre d'œuvres.

131

A partir du rubis 1.9.3, vous avez la méthode Module#private_constant, qui semble être exactement ce que vous vouliez:

class Person 
    SECRET='xxx'.freeze 
    private_constant :SECRET 

    def show_secret 
    puts "Secret: #{SECRET}" 
    end 
end 

Person.new.show_secret 
# => "Secret: xxx" 

puts Person::SECRET 
# NameError: private constant Person::SECRET referenced 
+5

Ceci est la bonne réponse, à mon humble avis. –

+1

C'est tellement génial. Je n'avais aucune idée que c'était même une chose. –

+0

Je ne vois pas cette méthode dans l'API 'Module' jusqu'à ce que http://www.ruby-doc.org/core-2.0.0/Module.html (http://www.ruby-doc.org/core -1.9.3/Module.html) –

Questions connexes