2015-05-20 8 views
15

posso fare attr_reader (e il relativo attr_writer e attr_accessor) il metodo (s) privata mettendo la dichiarazione in una sezione private:Perché un metodo delegato è pubblico quando dichiarato in una sezione privata?

class Foo 
private 
    attr_reader :b 
end 

Foo.new.b # => NoMethodError: private method `b' called for #<Foo:> 

Tuttavia, delegate e del def_delegate libreria standard di Ruby non funzionano questo Rails' modo. Questi metodi delegati sono sempre pubblici.

class Foo 
    attr_reader :b 
    def initialize 
    @b = 'b' 
    end 
end 

require 'forwardable' 
class Bar 
    attr_reader :foo 
    def initialize 
    @foo = Foo.new 
    end 
    extend Forwardable 
private 
    def_delegator :foo, :b 
end 

Bar.new.b # => "b" 

Rendere il privato delegazione è fatto facilmente cambiando a:

private def_delegator :foo, :b 

ma mi aspettavo un errore di NoMethodError per Bar.new.b sopra. Perché la delegazione non è privata?

La definizione del metodo di def_delegator (alias def_instance_delegator) copre soli rescue (blocchi rimossi):

def def_instance_delegator(accessor, method, ali = method) 
    line_no = __LINE__; str = %Q{ 
    def #{ali}(*args, &block) 
     #{accessor}.__send__(:#{method}, *args, &block) 
    end 
    } 
    module_eval(str, __FILE__, line_no) 
end 

Ciò significa module_eval non rispetta che è stato chiamato in una sezione private. Perché?

risposta

4

Sì, il problema è con module_eval perché imposta in modo esplicito la visibilità pubblica prima di valutare la stringa passata. Si comporta allo stesso modo in CRuby e JRuby. Ad esempio, il codice incriminato per CRuby è nella funzione eval_under.

Come hai capito, quando passi il metodo def_delegate a private diventa privato. def_delegate definisce prima il metodo passato come pubblico (dal modulo module_eval sottostante), quindi ripristina per la visibilità privata da private.

Non è 100% chiaro se il comportamento corrente di Module.module_eval è corretto o c'è un errore in Forwardable.def_instance_delegator. module_eval esempi nella guida alla documentazione per usarlo al di fuori della classe/modulo interessato e non si aspetta argomento di visibilità, quindi sembra logico che imposta la visibilità del metodo al pubblico.

La soluzione sarebbe o Module.module_eval maniglia argomento opzionale visibilità e rispetto visibilità corrente quando inviato implicita o esplicita self (dubbio se possibile) o fissare Forwardable.def_instance_delegator attuazione di definire con metodo più appropriato Module.define_method anziché module_eval. In ogni caso questo è un buon candidato per compilare una segnalazione di bug su http://bugs.ruby-lang.org.

0

Penso che questo è come dovrebbe funzionare. Considero sempre che i modificatori di visibilità influenzano l'ambito in cui sono scritti e non le chiamate provenienti da lì. In questo senso la chiamata a module_eval non sa che si trova all'interno di una sezione privata (potrebbe?).

0

Sembra che la seconda opzione funzioni mentre la prima non funziona perché Rails sta dicendo "module_eval this specific line". Quindi, quando si è privati ​​sulla stessa linea, si comprende che dovrebbe iniziare a trattarlo come una definizione di metodo privata. Questo sembra qualcosa che dovrebbe essere risolto dai manutentori di Rails, creare un problema per loro.

Problemi correlati