Если вы пришли из PHP или C #, вы можете не думать о терминах метапрограммирования — хотя оба языка могут выполнять метапрограммирование, он, похоже, не используется интенсивно. В Ruby дело обстоит иначе, а метапрограммирование — ОГРОМНАЯ часть Ruby.
Так что же такое метапрограммирование? По сути, это способ динамического изменения программ, например, добавление или изменение методов ПОСЛЕ запуска программы (или во время выполнения, как нам нравится это называть).
Отличным примером этого являются методы find_by_ * в rails. Если у вас есть модель с именем «Пользователь», в которой есть столбец «возраст», вы можете искать записи по возрасту с помощью магического метода User.find_by_age. Это достигается с помощью метода method_missing.
Если вы вызываете метод, который не существует, Ruby вызовет метод method_missing и передаст имя метода и все предоставленные вами аргументы, что означает, что вы можете динамически обрабатывать метод.
class MyClass def find(name, value) puts "You want results from #{name} with a value of #{value}" end def method_missing(id, *args) return self.find(Regexp.last_match(1), args[0]) if id.id2name =~ /find_by_(.+)/ raise NoMethodError end end m = MyClass.new m.find('name', 'madpilot') > You want results from name with a value of madpilot m.find_by_name('madpilot') > You want results from name with a value of madpilot m.search_by_name('madpilot') > NoMethodError: NoMethodError
Как видите, метода «find_by_name» определенно не существует, но Ruby достаточно умен, чтобы вызывать метод find с правильными параметрами. Мы выполнили регулярное выражение для имени метода, и если оно соответствует шаблону find_by_ [string], то он вызывает метод find с частью [string] в качестве первого параметра и первым аргументом в качестве второго параметр. Довольно мощно, тебе не кажется?
Просто подсказка — будьте осторожны с бесконечными циклами — если ваш метод method_missing не завершается, и вы вызываете метод, который не существует внутри method_missing, у вас будут всевозможные проблемы!