Предположим, у вас есть зоопарк, очень красивый зоопарк, с кучей диких животных. Конечно, как хранитель зоопарка, вам часто нужно найти конкретных животных на основе их потребностей и характеристик. Но поскольку зоопарк растет и растет, невозможно заранее знать, какими будут эти характеристики! Попробуем исправить это ...
Сначала давайте определим, что такое животное;
class Animal
def initialize(attributes)
@attributes = attributes
end
def [](value)
@attributes[value]
end
end
Простой. Теперь давайте построим зоопарк!
class Zoo
def animals
@animals ||= []
end
end
Что такое зоопарк без животных?
zoo = Zoo.new
zoo.animals << Animal.new(type: "Mighty Giraffe", legs: 4, region: 'Africa')
zoo.animals << Animal.new(type: "Fierce Pidgin", legs: 2, region: 'America')
zoo.animals << Animal.new(type: "Wild Boar", legs: 4, region: 'Africa')
Perfect. Теперь у нас есть зоопарк, полный животных. Теперь мы знаем, что все они имеют свои специфические характеристики, но мы все еще не можем их найти ... Было бы здорово, если бы мы могли искать таких животных?
zoo.find_animals_by_region('Africa')
Но помните, мы не знаем заранее все эти характеристики! Попробуем исправить это, добавив специальный метод в наш зоопарк.
class Zoo
def animals
@@animals ||= []
end
def method_missing(method_name, *args, &block)
# stuff here
end
end
Отлично, теперь мы можем поймать все вызовы неопределенных методов в нашем зоопарке, которые означают, что find_animals_by_something будет улов сразу же, как это не определенно! Более того, мы даже получаем имя метода, которое было использовано. Большой! Давайте использовать это в наших интересах.
class Zoo
def animals
@@animals ||= []
end
def method_missing(method_name, *args, &block)
if method_name.to_s.start_with?('find_animals_by_')
# here we go!
end
end
end
Здесь мы идем! Теперь мы улавливаем только отсутствующие методы, которые начинаются со специального ключевого слова «find_animals_by_». Давайте добавим немного логики там, и не забудьте вызвать super для нежелательных методов!
class Zoo
def animals
@@animals ||= []
end
def method_missing(method_name, *args, &block)
if method_name.to_s.start_with?('find_animals_by_')
find_animals_by_attribute(method_name[16..-1], args[0])
else
super(method_name, *args, &block)
end
end
def find_animals_by_attribute(attribute, value)
animals.select{ |animal| animal[attribute.to_sym] == value }
end
end
Done! Полностью функциональный зоопарк, в котором мы можем искать наших животных!