Metaprogramming with examples
Reflection:
Reflection allows you to obtain information about classes, modules, methods, and variables at runtime.
class Person
attr_accessor :name, :age
end
person = Person.new
person.name = "Alice"
puts person.class # Output: Person
puts person.methods # Output: list of methods available for the object
puts person.instance_variables # Output: [:@name]
In this example, we use reflection to retrieve information about the person
object. We obtain the class name using the class
method, the list of available methods using the methods
method, and the instance variables using the instance_variables
method.
Dynamic method definition:
Ruby allows you to define methods dynamically at runtime using constructs like define_method
.
class Person
attr_accessor :name
def add_custom_method(method_name)
define_method(method_name) do
puts "Custom method #{method_name} called!"
end
end
end
person = Person.new
person.add_custom_method(:greet)
person.greet # Output: Custom method greet called!
In this example, the add_custom_method
method dynamically defines a new method based on the given method name. The define_method
allows us to generate a method on the fly, and we can then call that method on the person
object.
Method missing:
Ruby's method_missing
method is called when an undefined method is invoked. By overriding this method, you can intercept method calls and dynamically handle them.
class DynamicHandler
def method_missing(name, *args)
puts "Undefined method #{name} called!"
end
end
handler = DynamicHandler.new
handler.undefined_method # Output: Undefined method undefined_method called!
In this example, we define a class with the method_missing
method overridden. Whenever an undefined method is called on an instance of DynamicHandler
, the method_missing
method is invoked and prints a message.
Open classes:
Ruby allows you to reopen and modify existing classes at runtime.
class String
def shout
upcase + "!"
end
end
message = "hello"
puts message.shout # Output: HELLO!
In this example, we reopen the String
class and add a new method called shout
. This allows us to call shout
on any string object, converting it to uppercase and appending an exclamation mark.
eval
andinstance_eval
:
Ruby provides methods like eval
and instance_eval
that allow you to execute arbitrary code dynamically.
class Calculator
def initialize(x, y)
@x = x
@y = y
end
end
calculator = Calculator.new(2, 3)
result = calculator.instance_eval("@x + @y")
puts result # Output: 5
In this example, we use instance_eval
to dynamically execute the expression @x + @y
within the context of the calculator
object. This allows us to access and operate on the instance variables of the object.
These examples showcase different aspects of metaprogramming in Ruby, including reflection, dynamic method definition, method missing, open classes, and code execution at runtime using eval
and instance_eval
. These features provide the ability to dynamically modify and extend code behavior, making Ruby a flexible and powerful language for metaprogramming.
Last updated