method_missing
— это мощный инструмент метапрограммирования в Ruby, который позволяет перехватывать вызовы методов, которые не определены в классе. Рассмотрим его применение подробно.
class DynamicResponder
def method_missing(method_name, *args, &block)
if method_name.to_s.start_with?('find_by_')
# Обработка динамического finder'а
attribute = method_name.to_s[8..-1]
find_by_attribute(attribute, args.first)
else
super
end
end
private
def find_by_attribute(attr, value)
# Реализация поиска
puts "Finding by #{attr} = #{value}"
end
end
Метод принимает три параметра:
method_name
- символ с именем вызываемого метода*args
- аргументы, переданные методу&block
- блок, если он был переданclass UserRepository
def initialize(users)
@users = users
end
def method_missing(name, *args)
if name.to_s =``` /^find_by_(.+)$/
find_by_attribute($1, args.first)
else
super
end
end
private
def find_by_attribute(attr, value)
@users.find { |user| user[attr.to_sym] == value }
end
end
class ApiProxy
def initialize(real_api)
@api = real_api
end
def method_missing(name, *args)
if @api.respond_to?(name)
puts "Logging call to #{name} with #{args}"
@api.send(name, *args)
else
super
end
end
end
class Settings
def initialize
@values = {}
end
def method_missing(name, *args)
if name.to_s.end_with?('=')
@values[name.to_s.chop.to_sym] = args.first
else
@values.fetch(name) { super }
end
end
end
Обязательно вызывайте super:
Определите respond_to_missing?:
respond_to?
нужно переопределить и этот методclass SmartHash
def method_missing(name, *args)
# ... реализация ...
end
def respond_to_missing?(name, include_private = false)
name.to_s.start_with?('find_by_') || super
end
end
method_missing
медленнее обычных методовЧтобы избежать постоянных вызовов method_missing
:
class DynamicFinder
def method_missing(name, *args)
if name.to_s =``` /^find_by_(.+)$/
define_finder_method($1)
send(name, *args)
else
super
end
end
private
def define_finder_method(attr)
define_singleton_method("find_by_#{attr}") do |value|
# Реализация поиска
end
end
end
Ограничивайте допустимые методы:
Не используйте для критически важной логики:
define_method:
Шаблон Strategy:
Delegator:
method_missing
— это мощный инструмент, который позволяет:
Ключевые правила использования:
super
для необработанных методовrespond_to_missing?
для консистентностиИспользуйте method_missing
разумно — это "острый нож" в арсенале Ruby, который может как упростить код, так и сделать его непредсказуемым.