Bird
Raised Fist0
Rubyprogramming~10 mins

Define_method with closures in Ruby - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Define_method with closures
Start
↓
Define method with define_method
↓
Method captures closure variables
↓
Call method
↓
Method uses captured variables
↓
Return result
↓
End
Shows how define_method creates a method that remembers variables from its surrounding context (closure) and uses them when called.
Execution Sample
Ruby
class Greeter
  def initialize(name)
    @name = name
    self.class.define_method(:greet) do
      "Hello, #{@name}!"
    end
  end
end

g = Greeter.new("Alice")
puts g.greet
Defines a method greet inside a class using define_method that remembers the instance variable @name and uses it when called.
Execution Table
StepActionEvaluationResult
1Create Greeter instance with name 'Alice'Calls initialize with @name = 'Alice'Instance variable @name set to 'Alice'
2Inside initialize, define method :greet with define_methodMethod greet captures @name from closureMethod greet created and remembers @name = 'Alice'
3Call g.greetExecute greet method bodyReturns string 'Hello, Alice!'
4Print outputputs prints returned stringOutput: Hello, Alice!
5EndNo more codeExecution stops
💡 Execution stops after printing the greeting message.
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
@namenil'Alice''Alice''Alice''Alice'
greet methodundefineddefined (captures @name='Alice')defined (captures @name='Alice')calleddefined (captures @name='Alice')
Key Moments - 2 Insights
Why does the greet method remember the value of @name even after initialize finishes?
Because define_method creates a closure that captures the surrounding context, including instance variables like @name, as shown in execution_table step 2.
What happens if we create another Greeter with a different name?
Each instance defines its own greet method capturing its own @name, so calling greet on different instances returns greetings with their respective names.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 3, what does the greet method return?
A"Hello, Alice!"
B"Hello, nil!"
C"Hello, World!"
DAn error
💡 Hint
Check the 'Result' column at step 3 in execution_table.
At which step is the greet method created and remembers the @name variable?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Look at the 'Action' and 'Result' columns in execution_table for step 2.
If we create a new Greeter with name 'Bob', what will greet return when called?
A"Hello, Alice!"
B"Hello, nil!"
C"Hello, Bob!"
DAn error
💡 Hint
Refer to key_moments about multiple instances and variable capture.
Concept Snapshot
define_method(:name) do ... end creates a method dynamically.
This method captures variables from its surrounding context (closure).
When called, it uses those captured variables.
Useful for dynamic behavior tied to instance data.
Closures keep variables alive beyond method definition.
Full Transcript
This example shows how Ruby's define_method can create a method that remembers variables from its surrounding context, called closures. We create a Greeter class that sets an instance variable @name. Inside initialize, define_method creates a greet method that uses @name. When we call greet, it returns a greeting with the stored name. The execution table traces creating the instance, defining the method with closure, calling it, and printing the result. The variable tracker shows @name stays 'Alice' and greet method captures it. Key moments explain why the method remembers @name and what happens with multiple instances. The quiz tests understanding of method creation, closure capture, and output. This helps beginners see how define_method and closures work together in Ruby.

Practice

(1/5)
1. What does define_method do in Ruby?
easy
A. Defines a class variable
B. Deletes an existing method
C. Calls a method immediately
D. Creates a method dynamically using a block

Solution

  1. Step 1: Understand the purpose of define_method

    define_method is used to create methods dynamically at runtime using a block of code.
  2. Step 2: Compare with other options

    Options B, C, and D describe different actions unrelated to define_method.
  3. Final Answer:

    Creates a method dynamically using a block -> Option D
  4. Quick Check:

    define_method creates methods dynamically [OK]
Hint: Remember: define_method builds methods with blocks [OK]
Common Mistakes:
  • Thinking define_method calls methods
  • Confusing define_method with deleting methods
  • Assuming it defines variables
2. Which of the following is the correct syntax to define a method named greet using define_method that returns "Hello"?
easy
A. def define_method(:greet) "Hello" end
B. define_method greet { return "Hello" }
C. define_method(:greet) { "Hello" }
D. define_method(:greet, "Hello")

Solution

  1. Step 1: Recall correct define_method syntax

    The correct syntax uses a symbol for the method name and a block: define_method(:name) { ... }.
  2. Step 2: Check each option

    def define_method(:greet) "Hello" end uses def incorrectly. define_method greet { return "Hello" } lacks symbol (greet undefined). define_method(:greet, "Hello") passes string instead of block. B matches correct syntax.
  3. Final Answer:

    define_method(:greet) { "Hello" } -> Option C
  4. Quick Check:

    Correct syntax uses symbol and block [OK]
Hint: Use symbol and block for define_method syntax [OK]
Common Mistakes:
  • Using method name without symbol
  • Incorrect block syntax
  • Using def inside define_method
3. What will be the output of this Ruby code?
class Person
  def initialize(name)
    @name = name
    self.class.define_method(:greet) { "Hello, #{@name}!" }
  end
end

p = Person.new("Alice")
puts p.greet
medium
A. Hello, Alice!
B. Hello, !
C. NoMethodError
D. SyntaxError

Solution

  1. Step 1: Understand closure and instance variable scope

    The block passed to define_method defines the method body. However, the string interpolation "Hello, #{@name}!" is evaluated immediately when define_method is called, not when the method is invoked. At that time, @name is nil because the block is defined in the class context, not the instance context.
  2. Step 2: Predict output

    Therefore, the method greet returns the string with @name interpolated as nil, resulting in "Hello, !".
  3. Final Answer:

    Hello, ! -> Option B
  4. Quick Check:

    String interpolation in define_method block evaluated immediately [OK]
Hint: String interpolation in define_method block is evaluated immediately [OK]
Common Mistakes:
  • Thinking @name is dynamically resolved inside the block
  • Expecting 'Hello, Alice!' due to misunderstanding of closure
  • Confusing instance and class scope
4. Identify the error in this code snippet:
class Calculator
  def initialize(x)
    @x = x
    self.class.define_method(:square) { @x * @x }
  end
end

calc = Calculator.new(4)
puts calc.square
medium
A. No error, outputs 16
B. Syntax error in define_method block
C. The block does not capture @x correctly, causing nil * nil error
D. The method square is not defined for instances

Solution

  1. Step 1: Analyze where define_method is called

    define_method on self.class defines an instance method square. The block executes in instance context.
  2. Step 2: Understand closure and instance variable scope

    @x resolved on instance: 4 * 4 = 16. No capture issue, no error.
  3. Final Answer:

    No error, outputs 16 -> Option A
  4. Quick Check:

    Instance vars work in class-level define_method [OK]
Hint: Instance vars work in class-level define_method blocks [OK]
Common Mistakes:
  • Thinking method undefined for instances
  • Expecting syntax error
  • Believing nil * nil error from poor capture
5. How can you fix this code so that each instance of Person has a greet method that correctly uses its own @name?
class Person
  def initialize(name)
    @name = name
    self.class.define_method(:greet) { "Hello, #{@name}!" }
  end
end

p1 = Person.new("Bob")
p2 = Person.new("Carol")
puts p1.greet
puts p2.greet
hard
A. Define greet method inside initialize using define_singleton_method
B. Use self.class.define_method but pass @name as parameter
C. Move @name to a class variable
D. Use def greet; "Hello, #{@name}!"; end inside initialize

Solution

  1. Step 1: Understand the problem with class-level define_method

    Class-level define_method in initialize redefines a shared instance method each time (inefficient, problematic for local var closures). Instance vars work via dynamic lookup.
  2. Step 2: Use define_singleton_method to define method per instance

    define_singleton_method defines on the instance's singleton class, giving each its own greet accessing own @name.
  3. Final Answer:

    Define greet method inside initialize using define_singleton_method -> Option A
  4. Quick Check:

    Use define_singleton_method for per-instance closures [OK]
Hint: Use define_singleton_method for instance-specific methods [OK]
Common Mistakes:
  • Trying to pass instance vars as parameters to class method
  • Using class variables instead of instance variables
  • Defining method with def inside initialize incorrectly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard