2011-01-08 3 views
5

У меня есть переменныеПреобразовать строку в имя переменной в рубин

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

Я хочу изменить значения этих переменных динамически.

<% 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 

Значение не присваивается. Есть ли способ присвоить значение переменной динамически?

+4

Делайте, делайте, используйте для этого массивы (или хеши). –

+3

Ответ на [2530112] (http://stackoverflow.com/questions/2530112) должен помочь, он рекомендует 'instance_variable_set'. –

+1

Динамическое создание имени переменной «на лету» можно выполнять на некоторых языках, включая Ruby, но в течение многих лет не пользуется популярностью и в большинстве случаев считается любопытством. Это приводит к путанице, которая приводит к проблемам обслуживания, поэтому обойти проблему и использовать хеш. Это также может привести к проблемам безопасности, если имена переменных поступают из введенного пользователем ввода или могут вызвать странные ошибки, если имя столкнулось с ранее созданной переменной. –

ответ

3

Я не думаю, что есть способ сделать это. Существует с переменными экземпляра или класса, но с локальными переменными очень редко возникает необходимость.

В вашем случае вы действительно должны иметь данные в хеше. Кроме того, логика вроде этого действительно не принадлежит erb. Вы хотите что-то вроде:

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

Это выполнимо с помощью eval, но вы правы, говоря, что это не должно быть сделано таким образом. Использование хэша вместо этого является лучшим решением. –

+1

Или вы можете передать этот блок в 'inject':' {| hash, day | hash.merge (day => 0)} ' – zetetic

2

Теперь, я знаю, что это cuestion немного старая, но есть более простой способ сделать это и с помощью Standart Рубина отправить метод. Это на самом деле один из методов, который делает Ruby настолько гибким в мире метапрограммирования.

Это фактически настройка конфигурации я использую в приложении 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 

Это DRY и очень легко понять. :)

0

Еще один ответ на этот старый вопрос.

В моем сценарии я хотел подсчитать, сколько раз в день появилось в течение нескольких дней (day_array). Мне не нужно было знать, не появился ли день в day_array, поэтому я не инициализировал хэш days_count как gunn в his answer.

Вот как я это сделал:

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 

Если скопировать и вставить выше в IRB, то:

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

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

В принципе, в соответствии с предыдущими ответами. Но, я думал, что дополнительный пример не может повредить.

Смежные вопросы