2010-04-18 10 views
6

Czy istnieje sposób na przesłonięcie ustawienia zmiennych instancji w Ruby?Jak się dowiedzieć, kiedy zmienna instancji zostanie ustawiona w Ruby

Powiedzmy ustawić instancję zmiennej:

@foo = "bar" 

mogę przechwycić że i coś zrobić (jak nagrać go ani nie stawia, na przykład)

Przypuszczam, próbuję zastąpić przypisanie operator dla wszystkich typów. Czy można to nawet zrobić?

Najlepszym mam wymyślić, jak dotąd, jest to:

class Module 
    def attr_log_accessor(*symbols) 
    symbols.each { | symbol | 
     module_eval("def #{symbol}() @#{symbol}; end") 
     module_eval("def #{symbol}=(val) 
         @#{symbol} = val 
         puts \"#{symbol} has changed\" 
        end") 
    } 
    end 
end 

Wtedy, kiedy zdefiniować akcesor i ustawić go, mój kod zostanie wykonany:

class Test 
    attr_log_accessor :foo 

    def DoSomething 
    self.foo = "bar" 
    end 
end 

Niestety, wymaga to od mnie napisania self.foo = "bar", zamiast @foo = "bar".

Jakieś myśli?

+0

tam 'trace_var' (http://www.ruby-doc.org/core/classes/Kernel.html#M005937), ale tylko dla globalnych zmiennych. –

+0

Istnieje również moduł Observable, który może być tak blisko jak to możliwe: http://www.oreillynet.com/ruby/blog/2006/01/ruby_design_patterns_observer.html Jednak może to wymagać użycia getter/setters zamiast bezpośrednio ustawiając zmienną instancji (co jest w zasadzie jak teraz to robisz) –

Odpowiedz

3

Nie możesz tego zrobić bezpośrednio. Najlepszym sposobem na uzyskanie dostępu do zmiennych instancji metodami getter/setter jest ich zastąpienie.

1

Możesz zadziwić z instance_variable_get, instance_variable_set i instance_variables. Więcej można znaleźć w tym artykule Ruby's Metaprogramming Toolbox.

Jeśli możesz opisać, dlaczego próbujesz to zrobić, możemy zaoferować lepszą metodę.

+0

Próbuję to zrobić, ponieważ dla konkretnych właściwości klasy, chcę powiadomić inne obiekty, gdy właściwości się zmieniają. Dokładniej, chodzi o integrację z .Net. Używam zdarzeń IronRuby i wypalania w zdarzeniu INotifyPropertyChanged.PropertyChanged. Chciałbym zadeklarować nieruchomość jako podlegającą obowiązkowi zgłoszenia: attr_notifiable: foo, lub coś i zawsze gdy @foo jest ustawione, uruchamia zdarzenie. W końcu self.foo zadziała, ale jeśli uda mi się wejść na parter (przypisanie do lokalnego var), to będzie dla mnie jeszcze bardziej użyteczny. –

0

Można to zrobić przy użyciu method_missing()

przykład:

def method_missing(name, *args) 
    attribute = name.to_s 
    if attribute =~ /=$/ 
    @attributes[attribute.chop] = args[0] 
    else 
    @attributes[attribute] 
    end 
end 

Jeśli masz przetworzeniu w swojej getter/setter, metoda ta szybko staje się nadęty.

Aby uzyskać więcej informacji, zapoznaj się ze źródłem OpenStruct. Ponadto wyciągnąłem ten kod z Metaprogramming Ruby (pg 52)

Należy również pamiętać, że spowoduje to wychwycenie wszystkich brakujących metod. Jeśli chcesz tylko przechwycić obj.[*]= wtedy musisz zmienić @attributes[attribute] do super

Powiązane problemy