2015-05-20 3 views
15

mogę attr_reader (a attr_writer i attr_accessor pokrewne) metodę (-y) prywatny poprzez umieszczenie oświadczenia w private odcinku:Dlaczego jest to metoda delegowany publiczny gdy zadeklarowana w sekcji prywatnej?

class Foo 
private 
    attr_reader :b 
end 

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

Jednak delegate i Ruby standardowe biblioteki def_delegate nie działają Rails' to droga. Te delegowane metody są zawsze publiczne.

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" 

Making prywatnej delegowania jest łatwo zrobić, zmieniając go do:

private def_delegator :foo, :b 

ale spodziewałem się błąd NoMethodError dla Bar.new.b powyżej. Dlaczego delegacja nie jest prywatna?

Definicja Sposób def_delegator (alias dla def_instance_delegator) znajduje się w odległości rescue (bloki usunięto):

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 

module_eval Oznacza to, że nie uznaje, że został on zwany w przekroju private. Czemu?

Odpowiedz

4

Tak, problem jest z module_eval ponieważ wyraźnie określa widoczność publiczną przed evaling przekazany ciąg. on zachowuje się w ten sam sposób w CRuby i JRuby. Na przykład, obciążone kod CRuby jest w eval_under funkcji.

Jak już ustaliłeś, po przejściu od def_delegate do private metoda staje się prywatna. def_delegate najpierw definiuje przekazaną metodę jako publiczną (przez moduł module_eval), następnie resetuje przez private do prywatnej widoczności.

Nie jest w 100% jasne, czy obecne zachowanie Module.module_eval jest poprawne, czy jest błąd w Forwardable.def_instance_delegator. module_eval przykłady w przewodniku po dokumentacji użycia go poza daną klasą/modułem i nie oczekuje argumentu widoczności, więc wydaje się logiczne, że ustawia widoczność metody na publiczną.

Rozwiązaniem byłoby albo Module.module_eval uchwyt Opcjonalny argument widoczność i respektować bieżący widoczność podczas wysłany do utajonego lub jawnego self wątpliwości (jeśli to możliwe) lub naprawić Forwardable.def_instance_delegator realizację zdefiniować metodę z bardziej odpowiednim Module.define_method zamiast module_eval. W każdym razie jest to dobry kandydat do napełniania raport o błędzie na http://bugs.ruby-lang.org.

0

Myślę, że to tak, jak powinno działać. Zawsze uważam, że modyfikatory widoczności wpływają na zakres, w którym są zapisywane, a nie na żadne z nich pochodzące. W tym sensie wywołanie module_eval nie wie, że znajduje się w sekcji prywatnej (czyż nie?).

0

Wygląda na to, że druga opcja działa, podczas gdy pierwsza nie, ponieważ Rails mówi "module_eval this specific line". Tak więc, kiedy masz prywatną na tej samej linii, rozumie ona, że ​​powinna zacząć traktować ją jako prywatną definicję metody. Wydaje się, że to coś, co powinni naprawić opiekunowie Rails, stworzyć dla nich problem.

Powiązane problemy