2014-09-07 15 views
5

Sto cercando di lavorare con i modificatori di accesso in Ruby. Ho:accesso ai metodi protetti in Ruby

class Person 
    def initialize (first_name, last_name, age) 
     @first_name=first_name 
     @last_name=last_name 
     @age=age 
    end 


    def show() 
     puts @first_name 
     puts @last_name 
     puts @age 
    end 

protected 
    def compare(other) 
    self.instance_variable_get(:@age)<=>other.instance_variable_get(:@age) 
    end 

end 

p1=Person.new("Some", "Body", "99") 
p1.show 
puts "\n" 

p2=Person.new("Who", "Ever", "21") 
p2.show 
puts "\n" 

p1.compare(p2) 

sto ottenendo l'errore "metodo protetto` confronto' chiamato per # (NoMethodError)" Ho provato a chiamare dall'interno della classe e senza. Ho incollato la versione senza qui. Ho pensato che i metodi protetti potevano essere chiamati su altri oggetti della stessa classe. Che cosa significa questo errore e come utilizzerei correttamente un metodo protetto qui? Grazie per l'aiuto.

+0

Vedo, quindi una classe protetta e privata si differenziano solo per la protezione consente per l'uso con una sottoclasse di la classe principale, ma nessuno dei due è direttamente accessibile. Grazie mille, mi stava facendo impazzire. –

risposta

0

è possibile chiamare un metodo protetto in un metodo pubblico della classe ...

class Person 
    def initialize (first_name, last_name, age) 
    @first_name=first_name 
    @last_name=last_name 
    @age=age 
    end 

    def same_age?(other) 
    age == other.age 
    end 

    def show 
    puts @first_name 
    puts @last_name 
    puts @age 
    end 

    protected 

    def age 
    @age 
    end 

end 

p1=Person.new("Some", "Body", "99") 
p1.show 
puts "\n" 

p2=Person.new("Who", "Ever", "21") 
p2.show 
puts "\n" 

# calls a method that calls a protected method 
p1.same_age?(p2) 
=> false 

# but you can't call #age directly... 
begin 
p1.age 
rescue NoMethodError 
    puts "no method error (protected)" 
end 
4

Hai la vista sbagliata della protected visibilità. Il Ruby doc dice:

La seconda visibilità è protetta. Quando si chiama un metodo protetto il mittente deve essere una sottoclasse del destinatario o il destinatario deve essere una sottoclasse del mittente. Altrimenti verrà generato un NoMethodError.

Quindi la limitazione della visibilità viene applicato mittente, non il ricevitore come quello che si pensava.

Se si desidera chiamare compare all'esterno dei metodi di istanza, è necessario utilizzare la visibilità pubblica. Se puoi, devi rimuovere il modificatore protected. Questo è il modo consigliato.

Se il codice è corretto e non è possibile modificare tale parte di codice, è possibile utilizzare il metodo Object#send. Object#send ignorerà il vincolo di visibilità e può accedere anche a metodi privati.

p1.send(:compare, p2) 

Oppure è possibile riaprire la classe e modificare la visibilità della classe compare:

# you code here 

# reopen and modify visibility 
class Person 
    public :compare 
end 

p1.compare(p2) 
+0

Whoa, quindi non c'è modo di avere un metodo sicuro nel rubino? È considerato una cattiva forma utilizzare il metodo di invio? Perché dovrebbe esserci il metodo in primo luogo, è solo per aggirare le restrizioni di accesso, o c'è una ragione o circostanza più appuntita per la quale è stato progettato? Apprezzo l'aiuto, sto solo cercando di capire. –

+0

'Object # send' non è un grosso problema dato che è sempre possibile eseguire il monkey patch e modificare comunque la visibilità del metodo. Se hai bisogno di metodi privati ​​per essere impercettibili con cui pasticciare, Ruby probabilmente non è la lingua che fa per te. – ZombieDev