Метапрограммирование в Ruby открывает двери в мир динамического создания и управления методами, классами и константами прямо во время выполнения кода. В этой статье разберём ключевые инструменты — от define_method до const_get — и их тонкости, которые помогут писать гибкий и DRY-код без лишнего дублирования. Особое внимание уделим различиям между похожими методами, чтобы избежать подводных камней в продакшене.
В прошлой статье мы обсуждали method_missing, теперь углубимся в метапрограммирование по полной: define_method, alias_method, const_get, send, и другие любимые конструкции архитекторов.
🧱 define_method — динамика и DRY
class User
[:name, :email].each do |attr|
define_method("get_#{attr}") do
instance_variable_get("@#{attr}")
end
end
end
Создаёт метод на лету, можно применять в любых DSL.
🪞 alias_method vs alias
class Greeter
def hello
"Hi!"
end
alias_method :greet, :hello
end
alias_method— метод, работает с символами (:name)alias— ключевое слово, требует имена (alias greet hello)
💣 remove_method vs undef_method
class Example
def hello; "hi"; end
remove_method :hello
end
remove_method— убирает только в текущем классеundef_method— убивает метод и из предков
🎯 send, public_send, send
"Ruby".send(:upcase) # => "RUBY"
"Ruby".public_send(:upcase) # => "RUBY"
"Ruby".__send__(:upcase) # => "RUBY"
sendвызывает даже приватноеpublic_send— только публичное__send__— fallback, если переопределилиsend
📦 const_get, const_defined?, const_set
module Admin
class Report; end
end
puts Admin.const_get(:Report) # => Admin::Report
puts Admin.const_defined?(:Report) # => true
Admin.const_set(:User, Class.new)
puts Admin::User.new.class.name # => Admin::User
Позволяет работать с константами, создавая и проверяя их в рантайме.
🧨 Комбо-подвох
class A
const_set(:B, Class.new)
end
puts A::B.name # => "A::B"
puts A.const_get(:C) # => 💥 NameError
🔚 Вывод: Метапрограммирование — это мощь, которая требует контроля. На собеседовании тебя проверят: не только на знание методов, но и на понимание их различий и применимости.