ruby - вызов метода для объекта с динамическим именем
У меня есть массив строк, которые представляют существующие имена объектов.
JoesDev = Dev.new
MarksDev = Dev.new
SamsDev = Dev.new
devices=['JoesDev', 'MarksDev', 'SamsDev' ]
Я хотел бы перебрать массив устройств, вызывая метод для объектов, в честь которых назван каждый элемент массива.
то есть;
JoesDev.method_name
MarksDev.method_name
SamsDev.method_name
Как я могу это сделать? Спасибо.
3 ответа
Вы можете использовать const_get
метод из Module
чтобы Ruby возвращал константу с указанным именем. В вашем случае он вернет Dev
экземпляр для любого имени устройства, которое вы даете ему.
С помощью .each
чтобы перебрать элементы, ваш код может выглядеть так
devices.each do |device_name|
device = self.class.const_get(device_name)
device.method_name
end
# Which can be shortened to
devices.each{ |dev| self.class.const_get(dev).method_name }
Тем не менее, есть лучшие способы реализовать этот тип вещей. Наиболее распространенным способом является использование Hash
, В вашем примере список устройств может выглядеть примерно так
devices = {
joe: Dev.new,
mark: Dev.new,
sam: Dev.new
}
Затем, перебирая устройства так же просто, как
devices.each do |dev|
dev.method_name
end
# Or
devices.each{ |dev| dev.method_name }
Дополнительно: если вы хотите немного пофантазировать, вы можете использовать блочную версию Hash::new
сделать добавление новых устройств чрезвычайно простым.
# Create the hash
devices = Hash.new{ |hash, key| hash[key] = Dev.new }
# Add the devices
devices['joe']
devices['mark']
devices['sam']
Этот тип хэша работает точно так же, как показано выше, но создаст новую запись, если данный ключ не может быть найден в хэше. Таким образом, потенциальная проблема с этим дизайном заключается в том, что вы можете случайно добавить новые устройства, если сделаете опечатку. Например
devices['jon'] # This would make a new Dev instance, which may be undesirable.
Один из способов - использовать eval- метод, который позволяет вам выполнять произвольные строки, как если бы они были кодом.
Итак, в вашем примере:
var_names.each{ |var_name| eval("#{var_name}.some_method") }
Само собой разумеется, очень опасно разрешать использовать нефильтрованные строки в качестве кода, могут случиться очень плохие вещи!