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.
devices.each{|name| self.class.const_get(name).method_name}

Один из способов - использовать eval- метод, который позволяет вам выполнять произвольные строки, как если бы они были кодом.

Итак, в вашем примере:

var_names.each{ |var_name| eval("#{var_name}.some_method") }

Само собой разумеется, очень опасно разрешать использовать нефильтрованные строки в качестве кода, могут случиться очень плохие вещи!

Другие вопросы по тегам