class DynamicFinder
def initialize(records)
@records = records
end
def method_missing(method_name, *args, &block)
if method_name.to_s =~ /^find_by_(.+)$/
attribute = $1
find_by_attribute(attribute, args.first)
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
method_name.to_s.start_with?('find_by_') || super
end
private
def find_by_attribute(attribute, value)
@records.find { |record| record[attribute.to_sym] == value }
end
end
# Usage:
users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
]
finder = DynamicFinder.new(users)
finder.find_by_name('Alice') # => { id: 1, name: 'Alice', ... }
finder.find_by_email('bob@example.com') # => { id: 2, ... }
class QueryBuilder
attr_reader :conditions
def initialize
@conditions = []
end
def self.build(&block)
builder = new
builder.instance_eval(&block)
builder
end
def where(field, value)
@conditions << { field: field, operator: '=', value: value }
self
end
def greater_than(field, value)
@conditions << { field: field, operator: '>', value: value }
self
end
def less_than(field, value)
@conditions << { field: field, operator: '<', value: value }
self
end
def to_sql
conditions.map { |c| "#{c[:field]} #{c[:operator]} #{c[:value]}" }.join(' AND ')
end
end
# Usage with DSL:
query = QueryBuilder.build do
where :status, 'active'
greater_than :age, 18
less_than :score, 100
end
puts query.to_sql
# => "status = active AND age > 18 AND score < 100"
class Configuration
SETTINGS = %i[database cache storage email].freeze
SETTINGS.each do |setting|
# Getter
define_method(setting) do
instance_variable_get("@#{setting}")
end
# Setter
define_method("#{setting}=") do |value|
instance_variable_set("@#{setting}", value)
end
# Predicate
define_method("#{setting}?") do
!!instance_variable_get("@#{setting}")
end
end
def configure(&block)
instance_eval(&block)
self
end
end
# Usage:
config = Configuration.new.configure do
self.database = 'postgresql'
self.cache = 'redis'
self.email = 'sendgrid'
end
config.database? # => true
config.storage? # => false
Ruby's metaprogramming enables dynamic method definition and interception. method_missing catches undefined method calls, allowing DSL creation and proxy patterns. I implement it carefully with respond_to_missing? for proper introspection. define_method creates methods dynamically at runtime, useful for reducing repetition. Class and instance variables can be manipulated via class_variable_set and instance_variable_set. send and public_send invoke methods dynamically. Metaprogramming powers Rails' magic—associations, validations, callbacks. I use it judiciously to create expressive APIs without sacrificing clarity. Understanding Ruby's object model—classes are objects, methods are objects—unlocks powerful patterns. Metaprogramming reduces boilerplate while maintaining Ruby's elegance and readability.