metaprogramming/advanced/lazy_evaluation.rb

tests/_examples/metaprogramming/advanced/lazy_evaluation.rb in the metorex repository.

# Lazy Evaluation: Defer computation until the value is needed
# Demonstrates: blocks as closures, memoization pattern

class Lazy
  def initialize(&block)
    @block = block
    @computed = false
    @value = nil
  end

  def value
    if !@computed
      @value = @block.call
      @computed = true
    end
    @value
  end

  def computed?
    @computed
  end
end

puts "=== Lazy Evaluation ==="

# The block is not called until .value is accessed
expensive = Lazy.new do
  puts "  (computing expensive value...)"
  42 * 42
end

puts "Created lazy value"
puts "Computed yet? #{expensive.computed?}"
puts "First access: #{expensive.value}"
puts "Computed now? #{expensive.computed?}"
puts "Second access: #{expensive.value}"

# Lazy chain: compose lazy computations
puts ""
puts "=== Lazy Chaining ==="

step1 = Lazy.new do
  puts "  (step 1: loading data...)"
  [10, 20, 30]
end

step2 = Lazy.new do
  data = step1.value
  puts "  (step 2: transforming data...)"
  total = 0
  data.each do |n|
    total += n
  end
  total
end

step3 = Lazy.new do
  sum = step2.value
  puts "  (step 3: formatting result...)"
  "Total: #{sum}"
end

puts "Pipeline created (nothing computed yet)"
puts "Final result: #{step3.value}"
puts "Accessing again (cached): #{step3.value}"

Output:

=== Lazy Evaluation ===
Created lazy value
Computed yet? false
  (computing expensive value...)
First access: 1764
Computed now? true
Second access: 1764

=== Lazy Chaining ===
Pipeline created (nothing computed yet)
  (step 1: loading data...)
  (step 2: transforming data...)
  (step 3: formatting result...)
Final result: Total: 60
Accessing again (cached): Total: 60