Defining and Calling Methods Dynamically in Ruby

Ruby's metaprogramming capabilities allow you to define and call methods dynamically at runtime, providing powerful flexibility in your code. For more on Ruby's dynamic features, check out our guide on ruby metaprogramming explained.

Understanding Dynamic Method Definition

Dynamic method definition allows you to create methods at runtime based on your program's needs. This is particularly useful for creating flexible, maintainable code that adapts to changing requirements. For more on Ruby's class system, see our guide on understanding open classes in Ruby advantages disadvantages.

Using define_method

The most common way to define methods dynamically is using define_method:

ruby
1class DynamicMethods
2 def initialize
3 @data = {}
4 end
5
6 def add_method(name, &block)
7 self.class.send(:define_method, name, &block)
8 end
9end
10
11dynamic = DynamicMethods.new
12dynamic.add_method(:greet) { |name| "Hello, #{name}!" }
13puts dynamic.greet("Alice") # Output: Hello, Alice!
14

For more on Ruby's object model, check out our guide on ruby eigenclass singleton class guide.

Dynamic Method Invocation

Using send

The send method allows you to call methods dynamically by their name:

ruby
1class Messenger
2 def hello(name)
3 "Hello, #{name}!"
4 end
5
6 def goodbye(name)
7 "Goodbye, #{name}!"
8 end
9end
10
11messenger = Messenger.new
12method_name = "hello"
13puts messenger.send(method_name, "Bob") # Output: Hello, Bob!
14

For more on method access control, see our guide on ruby access control modifiers difference.

Using method_missing

method_missing allows you to handle calls to undefined methods:

ruby
1class DynamicHandler
2 def method_missing(name, *args)
3 if name.to_s.start_with?('find_by_')
4 attribute = name.to_s.sub('find_by_', '')
5 "Finding by #{attribute}: #{args.first}"
6 else
7 super
8 end
9 end
10end
11
12handler = DynamicHandler.new
13puts handler.find_by_name("Alice") # Output: Finding by name: Alice
14

For more on method handling, check out our guide on difference between delegate and delegation in ruby.

Security Considerations

When using dynamic method definition and invocation, be cautious about security implications:

  1. Avoid eval: Using eval with user input can lead to security vulnerabilities
  2. Validate method names: Always validate dynamic method names
  3. Control access: Use proper access modifiers to protect sensitive methods

For more on security, see our guide on ruby security implications of eval.

Best Practices

1. Method Name Validation

Always validate method names before defining them:

ruby
1def safe_define_method(name)
2 if name.to_s.match?(/^[a-z_][a-zA-Z0-9_]*$/)
3 define_method(name) { yield }
4 else
5 raise "Invalid method name: #{name}"
6 end
7end
8

2. Use Blocks for Definition

Pass method implementations as blocks for better encapsulation:

ruby
1class API
2 def define_endpoint(name, &implementation)
3 define_singleton_method(name) do |*args|
4 instance_exec(*args, &implementation)
5 end
6 end
7end
8

3. Document Dynamic Methods

Maintain clear documentation for dynamically defined methods:

ruby
1class DocumentedDynamic
2 # @dynamic
3 # Defines greeting methods for each provided name
4 def self.create_greetings(*names)
5 names.each do |name|
6 define_method("greet_#{name}") do
7 "Hello, #{name}!"
8 end
9 end
10 end
11end
12

Related Resources

Ruby Fundamentals

Method Handling

Advanced Topics

Conclusion

Dynamic method definition and invocation in Ruby provides powerful tools for creating flexible and maintainable code. By following best practices and understanding the security implications, you can effectively use these features to enhance your Ruby applications.

Suggested Articles