2010-04-18 8 views
6

Existe-t-il un moyen de remplacer le paramètre des variables d'instance dans Ruby?Comment savoir quand une variable d'instance est définie dans Ruby

Disons que je mets une variable d'instance:

@foo = "bar" 

Puis-je intercepter cela et faire quelque chose (comme enregistrement ou met, par exemple)

Je suppose, je suis en train de passer outre l'affectation opérateur pour tous les types. Est-ce faisable?

Le meilleur que je suis venu avec, à ce jour, est la suivante:

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 

Puis, quand je définis l'accesseur et IMPOSEES, mon code est exécuté:

class Test 
    attr_log_accessor :foo 

    def DoSomething 
    self.foo = "bar" 
    end 
end 

Malheureusement, cela m'oblige à écrire self.foo = "bar", au lieu de @foo = "bar".

Des pensées?

+0

il y a 'trace_var' (http://www.ruby-doc.org/core/classes/Kernel.html#M005937), mais pour les vars globales seulement. –

+0

Il y a aussi le module Observable, qui peut être aussi proche de cela que possible: http://www.oreillynet.com/ruby/blog/2006/01/ruby_design_patterns_observer.html Cependant, cela peut nécessiter l'utilisation de getters/setters au lieu de Définir directement la variable d'instance (ce qui est fondamentalement la façon dont vous le faites maintenant) –

Répondre

3

Non, vous ne pouvez pas le faire directement. La meilleure approche consiste à accéder uniquement aux variables d'instance via les méthodes getter/setter et à les remplacer.

1

Vous pourriez jouer avec instance_variable_get, instance_variable_set et instance_variables. Plus peut être trouvé dans cet article Ruby's Metaprogramming Toolbox.

Si vous pouviez décrire pourquoi vous essayez de faire cela, nous pourrions être en mesure d'offrir une meilleure méthode.

+0

J'essaye de faire ceci, parce que pour des propriétés spécifiques sur la classe, je veux notifier d'autres objets quand les propriétés changent. Plus précisément, ceci est pour l'intégration avec .Net. J'utilise IronRuby et les événements de déclenchement sur l'événement INotifyPropertyChanged.PropertyChanged. Je voudrais déclarer une propriété comme notifiable: attr_notifiable: foo, ou quelque chose et chaque fois que @foo est défini, il déclenche l'événement. En fin de compte, self.foo fonctionnera, mais si je peux entrer au rez-de-chaussée (assignation au var local), alors cela me sera encore plus utile. –

0

Vous pouvez le faire en utilisant method_missing()

exemple:

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

Si vous avez dans votre traitement getter/setter, cette méthode serait rapidement devenir pléthorique.

Pour plus d'informations, consultez la source OpenStruct. En outre, j'ai tiré ce code de Metaprogramming Ruby (page 52)

Notez également que cela capture toutes les méthodes manquantes. Si vous voulez seulement intercepter obj.[*]= alors, vous devrez changer @attributes[attribute] à super

Questions connexes