假设你有一个动物园,一个非常漂亮的动物园,里面有一群野生动物。当然,作为动物园管理员,你经常需要根据它们的需求和特点来寻找特定的动物。但随着动物园的发展壮大,不可能提前知道这些特征会是什么!让我们尝试解决这个问题...
首先,让我们定义什么是动物;
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')
完美的。我们现在有一个满是动物的动物园。现在,我们知道它们都有其特定的特征,但我们仍然无法找到它们……能够像这样搜索我们的动物不是很好吗?
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 将立即被捕获,因为它是未定义的!此外,我们甚至得到了使用的 method_name。伟大的!让我们利用这个优势。
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
完毕!一个功能齐全的动物园,我们可以在其中搜索我们的动物!