metaprogramming/blocks_as_objects.rb

tests/_examples/metaprogramming/blocks_as_objects.rb in the metorex repository.

# Blocks as First-Class Objects in Metorex
# Demonstrates that blocks can be assigned, passed, returned, and manipulated like any other value

puts "=== Blocks as First-Class Objects ==="
puts ""

# Example 1: Assigning blocks to variables
puts "1. Assigning blocks to variables:"
double = lambda do |x| x * 2 end
result = double.call(5)
puts "double.call(5) = #{result}"
puts ""

# Example 2: Multiple parameter blocks
puts "2. Multiple parameter blocks:"
add = lambda do |a, b| a + b end
sum = add.call(3, 7)
puts "add.call(3, 7) = #{sum}"
puts ""

# Example 3: Passing blocks as arguments
puts "3. Passing blocks as arguments to functions:"
def apply_twice(func, value)
  result = func.call(value)
  func.call(result)
end

increment = lambda do |n| n + 1 end
final = apply_twice(increment, 5)
puts "apply_twice(increment, 5) = #{final}"
puts ""

# Example 4: Returning blocks from functions
puts "4. Returning blocks from functions (closures):"
def make_multiplier(factor)
  lambda do |x| x * factor end
end

times_three = make_multiplier(3)
times_ten = make_multiplier(10)

result3 = times_three.call(4)
result10 = times_ten.call(4)

puts "times_three.call(4) = #{result3}"
puts "times_ten.call(4) = #{result10}"
puts ""

# Example 5: Blocks capturing variables (closures)
puts "5. Blocks capturing variables from outer scope:"
counter_value = 0

increment_counter = lambda do ||
  counter_value = counter_value + 1
  counter_value
end

puts "First call: #{increment_counter.call}"
puts "Second call: #{increment_counter.call}"
puts "Third call: #{increment_counter.call}"
puts ""

# Example 6: Partial application pattern
puts "6. Partial application pattern:"
def make_greeter(greeting)
  lambda do |name| "#{greeting}, #{name}!" end
end

say_hello = make_greeter("Hello")
say_goodbye = make_greeter("Goodbye")

puts say_hello.call("Alice")
puts say_goodbye.call("Bob")
puts ""

puts "=== Blocks are truly first-class objects! ==="

Output:

=== Blocks as First-Class Objects ===

1. Assigning blocks to variables:
double.call(5) = 10

2. Multiple parameter blocks:
add.call(3, 7) = 10

3. Passing blocks as arguments to functions:
apply_twice(increment, 5) = 7

4. Returning blocks from functions (closures):
times_three.call(4) = 12
times_ten.call(4) = 40

5. Blocks capturing variables from outer scope:
First call: 1
Second call: 2
Third call: 3

6. Partial application pattern:
Hello, Alice!
Goodbye, Bob!

=== Blocks are truly first-class objects! ===