Metaprogramming in Ruby
Ruby's metaprogramming capabilities allow you to write code that writes code, making it highly flexible and dynamic.
Dynamic Method Definition
Use define_method
to define methods at runtime.
class MyClass
define_method :dynamic_method do |arg|
puts "Dynamic method called with #{arg}"
end
end
obj = MyClass.new
obj.dynamic_method("Hello")
Open Classes
Ruby allows you to reopen and modify existing classes, even built-in ones.
class String
def shout
self.upcase + "!"
end
end
puts "hello".shout # Output: HELLO!
Dynamic Method Calls
Use send
to call methods dynamically.
class MyClass
def my_method(arg)
puts "Called with #{arg}"
end
end
obj = MyClass.new
obj.send(:my_method, "Hello") # Output: Called with Hello
Class Macros
Class macros are methods that generate code at the class level. A common example is attr_accessor
.
class MyClass
def self.create_method(name)
define_method(name) do
puts "Method #{name} called"
end
end
end
MyClass.create_method(:new_method)
obj = MyClass.new
obj.new_method # Output: Method new_method called
Method Missing
Use method_missing
to handle calls to undefined methods.
class MyClass
def method_missing(name, *args)
puts "Method #{name} called with #{args}"
end
end
obj = MyClass.new
obj.undefined_method("Hello") # Output: Method undefined_method called with ["Hello"]
Reflection
Ruby provides reflection methods to inspect and manipulate objects at runtime.
class MyClass
def my_method
puts "Hello"
end
end
obj = MyClass.new
puts obj.class # Output: MyClass
puts obj.methods(false) # Output: [:my_method]
Best Practices
- Avoid Overuse: Metaprogramming can make code harder to read and debug. Use it sparingly.
- Documentation: Document metaprogramming code thoroughly to help others understand its purpose.
- Testing: Write tests for metaprogramming code to ensure it behaves as expected.
- Performance: Be mindful of performance implications, especially in large applications.