2011-01-08 6 views
5

J'ai des variableschaîne Convertir nom variable Ruby

<% mon_has_two_sets_of_working_hours = 0 %> 
<% tue_has_two_sets_of_working_hours = 0 %> 
<% wed_has_two_sets_of_working_hours = 0 %> 

Je souhaite modifier les valeurs de ces variables dynamiquement.

<% days_array = ['mon', 'tue', 'wed'] %> 

<% days_array.each do |day| %> 
    <% if condition? %> 
    # here i want to set %> 
    <% "#{day}__has_two_sets_of_working_hours" = 1 %> 
    end 
end 

La valeur n'est pas affectée. Est-il possible d'attribuer dynamiquement une valeur à une variable?

+4

Faites, utilisez, utilisez des tableaux (ou des tables de hachage) pour cela. –

+3

La réponse à [2530112] (http://stackoverflow.com/questions/2530112) devrait aider, il recommande 'instance_variable_set'. –

+1

Créer dynamiquement un nom de variable à la volée est faisable dans certaines langues, y compris Ruby, mais est tombé en disgrâce depuis des années, et est considéré comme une curiosité surtout. Cela conduit à la confusion qui conduit à des problèmes de maintenance, donc contournez le problème et utilisez un hash. Cela peut également conduire à des problèmes de sécurité si les noms de variables proviennent d'une entrée fournie par l'utilisateur, ou pourrait causer des bogues bizarres si un nom est entré en collision avec une variable précédemment créée. –

Répondre

3

Je ne pense pas qu'il existe un moyen de le faire. Il y a des variables d'instance ou de classe, mais avec des variables locales, il y a très rarement un bon besoin.

Dans votre cas, vous devriez vraiment avoir les données dans un hachage. Aussi, une logique comme celle-ci n'appartient vraiment pas à erb. Vous voulez quelque chose comme:

working_hour_sets = %w[mon tue wed thu fri sat sun].inject({}) do |hash, day| 
    hash[day]=0; 
    hash 
end 
# puts working_hour_sets #=> {"wed"=>0, "sun"=>0, "thu"=>0, "mon"=>0, "tue"=>0, "sat"=>0, "fri"=>0} 

working_hour_sets.each do |day, value| 
    working_hour_sets[day] = 1 if condition? 
end 
+1

Il est faisable d'utiliser eval, mais vous avez raison de dire que cela ne devrait pas être fait de cette façon. L'utilisation d'un hachage à la place est une meilleure solution. –

+1

Ou vous pouvez passer ce bloc à 'injecter':' {| hash, day | hash.merge (day => 0)} ' – zetetic

2

Maintenant, je sais que ce cuestion est un peu vieux, mais il y a un moyen de faire cela et plus facile utilise la méthode Ruby envoyer standart. C'est en fait l'une des méthodes qui rendent Ruby si agile dans le monde de la métaprogrammation.

Ceci est en fait un paramètre de configuration que je l'utilise dans une application Rails:

# In a YAML  
twitter: 
    consumer_key: 'CONSUMER-KEY' 
    consumer_secret: 'CONSUMER-SECRET' 
    oauth_token: 'OAUTH-KEY' 
    oauth_token_secret: 'OAUTH-SECRET' 

... 

# And in your file.rb 
config = YAML.load_file(Rails.root.join("config", "social_keys.yml"))[Rails.env]['twitter'] 

Twitter.configure do |twitter| 
    config.each_key do |k| 
    twitter.send("#{k}=", config[k]) 
    end 
end 

Il est sec et très facile à comprendre. :)

0

Encore une autre réponse à cette vieille question.

Dans mon scénario, je voulais compter combien de fois un jour apparaissait dans un tableau de jours (day_array). Je n'avais pas besoin de savoir si un jour ne s'affichait pas dans day_array, donc je n'ai pas initialisé le hachage days_count comme gunn l'a fait dans his answer.

Voilà comment je l'ai fait:

def count_days(day_array) 
    days_count = {} 
    day_array.each do |day| 
    days_count[day].nil? ? days_count[day] = 1 : days_count[day] = days_count[day] + 1 
    end 
    puts days_count 
end 

Si je copier et coller ci-dessus dans RIR, puis:

> count_days(%w[SU MO]) 
{"SU"=>1, "MO"=>1} 

> count_days(%w[SU SU MO]) 
{"SU"=>2, "MO"=>1} 

En fait, en accord avec les réponses précédentes. Mais, je pensais qu'un exemple supplémentaire ne pouvait pas faire de mal.