Metaprogramming Intro

Ruby is a dynamic, beginner-friendly programming language whose open, flexible object model makes metaprogramming — code that writes and inspects code at runtime — both natural and powerful.

Learn Metaprogramming Intro in our free Ruby course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end of this lesson you'll call methods dynamically with send, generate methods with define_method, and intercept unknown calls with method_missing.

What You'll Learn in This Lesson

1️⃣ Dynamic Calls and Introspection

send invokes a method named by a symbol or string, so you can decide which method to call at runtime. Pair it with introspection — respond_to? , instance_methods , ancestors — to ask objects about themselves.

2️⃣ Generating and Intercepting Methods

define_method creates methods at runtime, so you can generate a family of similar methods from a list — no copy-paste. method_missing catches calls to methods that don't exist, letting an object respond to names it was never explicitly given.

Your turn. Generate getter methods from the keys of a settings hash with define_method . Confirm the TODO , then run it.

Route a list of command strings to methods using send — the core of how CLIs dispatch input. Run with ruby dispatch.rb .

📋 Quick Reference — Metaprogramming

Practice quiz

What does metaprogramming mean?

  • writing tests
  • compiling code
  • writing code that writes or inspects code at runtime
  • obfuscating code

Answer: writing code that writes or inspects code at runtime. Metaprogramming generates or examines code while the program runs.

What does calc.send(:add, 2, 3) do?

  • calls the add method with 2 and 3
  • defines add
  • raises an error
  • returns the symbol :add

Answer: calls the add method with 2 and 3. send invokes a method named by a symbol or string, the same as calc.add(2, 3).

send can accept the method name as:

  • only a symbol
  • only a string
  • only a method object
  • a symbol or a string

Answer: a symbol or a string. send takes the name as either a symbol or a string.

Which is safer because it respects method visibility?

  • send
  • public_send
  • __send__
  • call

Answer: public_send. public_send will not invoke private methods, unlike send.

What does respond_to?(:add) return when the method exists?

  • true
  • nil
  • false
  • the method object

Answer: true. respond_to? returns true when the object has that method.

What does define_method do?

  • deletes a method
  • calls a method
  • creates a method at runtime
  • renames a class

Answer: creates a method at runtime. define_method creates methods programmatically, often in a loop.

An advantage of define_method over def is that its body:

  • runs faster always
  • can close over local variables in scope
  • needs no name
  • is always private

Answer: can close over local variables in scope. A define_method block closes over surrounding locals; a plain def cannot.

What does method_missing intercept?

  • syntax errors
  • all method calls
  • private methods only
  • calls to methods the object does not have

Answer: calls to methods the object does not have. Ruby calls method_missing when you invoke an undefined method.

When overriding method_missing, you should also define:

  • initialize
  • respond_to_missing?
  • to_s
  • method_added

Answer: respond_to_missing?. respond_to_missing? keeps respond_to? honest about dynamic methods.

Which familiar feature is itself an example of metaprogramming?

  • puts
  • require
  • attr_accessor
  • if/else

Answer: attr_accessor. attr_accessor defines getter/setter methods for you at runtime.