Skip to content
Ruby

Metaprogramming

Define methods dynamically, intercept with method_missing, and build DSLs.

By EZ4Code Team
metaprogrammingdsl

Code

# define_method
class Calculator
  [:add, :sub, :mul, :div].each do |op|
    define_method(op) do |a, b|
      case op
      when :add then a + b
      when :sub then a - b
      when :mul then a * b
      when :div then a.to_f / b
      end
    end
  end
end

c = Calculator.new
puts c.add(2, 3)
puts c.div(7, 2)

# method_missing for dynamic dispatch
class FlexibleHash
  def initialize
    @data = {}
  end

  def method_missing(name, *args)
    if name.to_s.end_with?("=")
      @data[name.to_s.chomp("=").to_sym] = args.first
    else
      @data[name]
    end
  end

  def respond_to_missing?(*)
    true
  end
end

h = FlexibleHash.new
h.name = "Alice"
h.age = 30
puts h.name

# send to call by name
puts "hello".send(:upcase)

# eval
puts eval("3 * 4 + 2")

# Class macro via instance_eval
class Config
  attr_reader :settings
  def initialize(&blk)
    @settings = {}
    instance_eval(&blk) if blk
  end
  def method_missing(name, value = nil)
    @settings[name] = value
  end
end

cfg = Config.new do
  host "localhost"
  port 3000
end
puts cfg.settings.inspect

Explanation

Ruby opens classes at runtime so methods can be defined dynamically with define_method. method_missing intercepts calls to undefined methods, enabling fluent interfaces and DSLs. instance_eval changes self inside a block, letting configuration blocks read as natural sentences.

More Ruby Snippets