Question

Je ne suis pas entièrement sûr que cela soit possible dans Ruby, mais j'espère qu'il existe un moyen simple de le faire.Je souhaite déclarer une variable et connaître plus tard le nom de la variable.Autrement dit, pour ce simple extrait :

foo = ["goo", "baz"]

Comment puis-je récupérer le nom du tableau (ici, "foo") ?Si c'est effectivement possible, cela fonctionne-t-il sur n'importe quelle variable (par exemple, scalaires, hachages, etc.) ?

Modifier:Voici ce que j'essaie essentiellement de faire.J'écris un serveur SOAP qui entoure une classe avec trois variables importantes, et le code de validation est essentiellement le suivant :

  [foo, goo, bar].each { |param|
      if param.class != Array
        puts "param_name wasn't an Array. It was a/an #{param.class}"
        return "Error: param_name wasn't an Array"
      end
      }

Ma question est alors :Puis-je remplacer les instances de « param_name » par foo, goo ou bar ?Ces objets sont tous des tableaux, donc les réponses que j'ai reçues jusqu'à présent ne semblent pas fonctionner (à l'exception de la réingénierie du tout, ala réponse de dbr)

Était-ce utile?

La solution

Et si vous retourniez votre problème ?Au lieu d'essayer d'obtenir des noms à partir de variables, récupérez les variables à partir des noms :

["foo", "goo", "bar"].each { |param_name|
  param = eval(param_name)
  if param.class != Array
    puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
    return "Error: #{param_name} wasn't an Array"
  end
  }

S'il y avait une chance qu'une des variables ne soit pas définie du tout (au lieu de ne pas être un tableau), vous voudriez ajouter "rescue nil" à la fin de la ligne "param = ..." pour conserver l'évaluation. de lever une exception...

Autres conseils

Vous devez repenser votre solution.Même si vous pourrait faites-le (vous ne pouvez pas), la question n’a tout simplement pas de réponse raisonnable.

Imaginez une méthode get_name.

a = 1
get_name(a)

Tout le monde pourrait probablement être d'accord, cela devrait renvoyer « a »

b = a
get_name(b)

Doit-il renvoyer « b », ou « a », ou un tableau contenant les deux ?

[b,a].each do |arg|
  get_name(arg)
end

Doit-il renvoyer « arg », « b » ou « a » ?

def do_stuff( arg )
  get_name(arg)
do
do_stuff(b)

Doit-il renvoyer « arg », « b » ou « a », ou peut-être le tableau de tous ?Même s’il renvoyait un tableau, quel serait l’ordre et comment saurais-je interpréter les résultats ?

La réponse à toutes les questions ci-dessus est "Cela dépend de la chose particulière que je veux à l'époque". Je ne sais pas comment vous pourriez résoudre ce problème pour Ruby.

Il semble que vous essayiez de résoudre un problème qui a une solution beaucoup plus simple.

Pourquoi ne pas simplement stocker les données dans un hachage ?Si tu fais..

data_container = {'foo' => ['goo', 'baz']}

..il est alors tout à fait trivial d'obtenir le nom 'foo'.

Cela dit, vous n'avez donné aucun contexte au problème, il peut donc y avoir une raison pour laquelle vous ne pouvez pas le faire.

[modifier] Après clarification, je vois le problème, mais je ne pense pas que ce soit le problème.Avec [foo, bar, bla], c'est équivalent à dire ['content 1', 'content 2', 'etc'].Le nom réel des variables est (ou plutôt devrait être) totalement hors de propos.Si le nom de la variable est important, c'est exactement pourquoi les hachages existent.

Le problème ne vient pas de l'itération sur [foo, bar] etc., c'est le problème fondamental de la façon dont le serveur SOAP renvoie les données et/ou de la façon dont vous essayez de les utiliser.

La solution, je dirais, est soit de faire en sorte que le serveur SOAP renvoie des hachages, soit, puisque vous savez qu'il y aura toujours trois éléments, ne pouvez-vous pas faire quelque chose comme...

{"foo" => foo, "goo" => goo, "bar"=>bar}.each do |param_name, param|
      if param.class != Array
        puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
        puts "Error: #{param_name} wasn't an Array"
      end
end

OK, cela fonctionne également dans les méthodes d'instance et, en fonction de vos besoins spécifiques (celui que vous avez mis dans le commentaire), vous pouvez faire ceci :

local_variables.each do |var|
  puts var if (eval(var).class != Fixnum)
end

Remplacez simplement Fixnum avec votre vérification de type spécifique.

Je ne connais aucun moyen d'obtenir un nom de variable locale.Mais vous pouvez utiliser le instance_variables méthode, cela renverra un tableau de tous les noms de variables d’instance dans l’objet.

Appel simple :

object.instance_variables

ou

self.instance_variables

pour obtenir un tableau de tous les noms de variables d'instance.

Bâtir sur Josh Moore, quelque chose comme ceci ferait probablement l'affaire :

# Returns the first instance variable whose value == x
# Returns nil if no name maps to the given value
def instance_variable_name_for(x)
  self.instance_variables.find do |var|
    x == self.instance_variable_get(var)
  end
end

Il y a Kernel::local_variables, mais je ne suis pas sûr que cela fonctionnera pour les variables locales d'une méthode, et je ne sais pas si vous pouvez la manipuler de manière à faire ce que vous souhaitez obtenir.

Excellente question.Je comprends parfaitement votre motivation.Permettez-moi de commencer par noter qu'il existe certains types d'objets spéciaux qui, dans certaines circonstances, ont une connaissance de la variable à laquelle ils ont été affectés.Ces objets spéciaux sont par exemple. Module instances, Class des cas et Struct instances:

Dog = Class.new
Dog.name # Dog

Le problème est que cela ne fonctionne que lorsque la variable à laquelle l'affectation est effectuée est une constante.(Nous savons tous que les constantes Ruby ne sont rien de plus que des variables émotionnellement sensibles.) Ainsi :

x = Module.new # creating an anonymous module
x.name #=> nil # the module does not know that it has been assigned to x
Animal = x # but will notice once we assign it to a constant
x.name #=> "Animal"

Ce comportement des objets conscients des variables auxquelles ils ont été affectés est communément appelé magie constante (car il est limité aux constantes).Mais c'est hautement souhaitable magie constante ne fonctionne que pour certains objets :

Rover = Dog.new
Rover.name #=> raises NoMethodError

Heureusement, J'ai écrit un joyau y_support/name_magic, qui s'occupe de cela pour vous :

 # first, gem install y_support
require 'y_support/name_magic'

class Cat
  include NameMagic
end

Le fait que cela ne fonctionne qu'avec des constantes (c.-à-d.variables commençant par une majuscule) n’est pas une si grande limitation.En fait, cela vous donne la liberté de nommer ou non vos objets à votre guise :

tmp = Cat.new # nameless kitty
tmp.name #=> nil
Josie = tmp # by assigning to a constant, we name the kitty Josie
tmp.name #=> :Josie

Malheureusement, cela ne fonctionnera pas avec les littéraux de tableau, car ils sont construits en interne sans utiliser #new méthode, sur laquelle NameMagic repose.Par conséquent, pour réaliser ce que vous souhaitez, vous devrez sous-classer Array:

require 'y_support/name_magic'
class MyArr < Array
  include NameMagic
end

foo = MyArr.new ["goo", "baz"] # not named yet
foo.name #=> nil
Foo = foo # but assignment to a constant is noticed
foo.name #=> :Foo

# You can even list the instances
MyArr.instances #=> [["goo", "baz"]]
MyArr.instance_names #=> [:Foo]

# Get an instance by name:
MyArr.instance "Foo" #=> ["goo", "baz"]
MyArr.instance :Foo #=> ["goo", "baz"]

# Rename it:
Foo.name = "Quux"
Foo.name #=> :Quux

# Or forget the name again:
MyArr.forget :Quux
Foo.name #=> nil

# In addition, you can name the object upon creation even without assignment
u = MyArr.new [1, 2], name: :Pair
u.name #=> :Pair
v = MyArr.new [1, 2, 3], ɴ: :Trinity
v.name #=> :Trinity

J'ai atteint le comportement constant d'imitation de la magie en rechercher toutes les constantes dans tous les espaces de noms de l'espace objet Ruby actuel.Cela fait perdre une fraction de seconde, mais comme la recherche n'est effectuée qu'une seule fois, il n'y a aucune perte de performances une fois que l'objet a trouvé son nom.À l'avenir, l'équipe principale de Ruby a promis const_assigned crochet.

Vous ne pouvez pas, vous devez retourner à la planche à dessin et repenser votre solution.

Foo n'est qu'un emplacement pour contenir un pointeur vers les données.Les données n'ont aucune connaissance de ce qui les pointe.Dans les systèmes Smalltalk, vous pouvez demander à la VM tous les pointeurs vers un objet, mais cela ne vous obtiendrait que l'objet contenant la variable foo, pas foo lui-même.Il n'existe aucun moyen réel de référencer une variable dans Ruby.Comme mentionné dans une réponse, vous pouvez toujours placer une balise dans les données qui fait référence à leur origine ou autre, mais ce n'est généralement pas une bonne approche pour la plupart des problèmes.Vous pouvez utiliser un hachage pour recevoir les valeurs en premier lieu, ou utiliser un hachage pour passer à votre boucle afin de connaître le nom de l'argument à des fins de validation, comme dans la réponse de DBR.

La chose la plus proche d'une vraie réponse à votre question est d'utiliser la méthode Enumerable each_with_index au lieu de each, ainsi :

my_array = [foo, baz, bar]
my_array.each_with_index do |item, index|
  if item.class != Array
    puts "#{my_array[index]} wasn't an Array. It was a/an #{item.class}"
  end
end

J'ai supprimé l'instruction return du bloc que vous passiez à each/each_with_index car elle ne faisait/ne signifiait rien.Each et each_with_index renvoient tous deux le tableau sur lequel ils fonctionnaient.

Il y a aussi quelque chose à propos de la portée des blocs qui mérite d'être noté ici :si vous avez défini une variable en dehors du bloc, elle sera disponible à l'intérieur de celui-ci.En d’autres termes, vous pouvez faire référence à foo, bar et baz directement à l’intérieur du bloc.L'inverse est pas vrai:les variables que vous créez pour la première fois à l’intérieur du bloc ne seront pas disponibles en dehors de celui-ci.

Enfin, la syntaxe do/end est préférée pour les blocs multilignes, mais c'est simplement une question de style, bien qu'elle soit universelle dans le code Ruby de tout millésime récent.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top