web-dev-qa-db-fra.com

Indéfinir la variable en Ruby

Supposons que j'utilise irb et saisis a = 5. Comment puis-je supprimer la définition de a afin que taper a renvoie une NameError?

Un peu de contexte: plus tard je veux faire ceci:

context = Proc.new{}.binding
context.eval 'a = 5'
context.eval 'undef a'  # though this doesn't work.
44
Peter

Il existe des méthodes remove_class_variable , remove_instance_variable et remove_const mais il n'existe actuellement aucun équivalent pour les variables locales.

44
mikej

Vous pouvez éviter de dé-déclarer la variable en réduisant la portée dans laquelle la variable existe:

def scope 
  yield
end

scope do 
  b = 1234
end

b  # undefined local variable or method `b' for main:Object
21
Daniel

Vous pouvez toujours "effacer" le registre de variables locales de irb en invoquant un sous-shell irb. Réfléchissez au fonctionnement de Bash Shells en ce qui concerne les variables d'environnement non déclarées. Puisque vous avez parlé du mode interactif, cette solution devrait fonctionner pour cela. 

En ce qui concerne le code de production, je ne voudrais pas indéfinir les variables locales dans le cadre d’une solution - les hachages à clé seraient probablement meilleurs pour ce type de scénario.

Voici ce que je veux dire:

$ irb
irb(main):001:0> a = "a"
=> "a"
irb(main):002:0> defined? a
=> "local-variable"
irb(main):003:0> irb # step into subshell with its own locals
irb#1(main):001:0> defined? a
=> nil
irb#1(main):002:0> a
NameError: undefined local variable or method `a' for main:Object
    from /Users/dean/.irbrc:108:in `method_missing'
    from (irb#1):2
irb#1(main):003:0> exit
=> #<IRB::Irb: @context=#<IRB::Context:0x1011b48b8>, @signal_status=:IN_EVAL, @scanner=#<RubyLex:0x1011b3df0>>
irb(main):004:0> a # now we're back and a exists again
=> "a"
13
Dean Radcliffe

Actuellement, vous n'avez aucun moyen de supprimer les variables globales, les variables locales et les variables de classe. Vous pouvez supprimer les constantes en utilisant la méthode "remove_const"

0
Nakul

Dans l'esprit de la question, vous pouvez limiter la variable à une étendue, en supposant que vous êtes d'accord avec le verrouillage d'autres variables locales sur la même étendue. Cela est particulièrement utile si vous définissez quelque chose dans une classe et que vous ne voulez pas que la variable locale reste dans la déclaration de la classe.

La seule façon dont je peux penser à faire ceci est avec Integer#times ou Array#each comme ceci:

1.times do |a|
  a = 5
  # code…
end

[5].each do |a|
  # code…
end

Il existe probablement d'autres moyens, même plus propres, de limiter le nombre de blocs à un autre. Ce ne sont pas aussi propres que je voudrais et j'aimerais voir si quelqu'un a une méthode plus propre à utiliser pour faire cela.

0
RWDJ