Report abuse

The class implementation


			
class Summer
  @@defines = {}

  class Bleak
    class BleakError < RuntimeError; end
    class TermProcNotDefinedError < BleakError; end
    class SuccProcNotDefinedError < BleakError; end

    def sum(term, a, succ, b)
      return 0 if a > b
      term.call(a) + sum(term, succ.call(a), succ, b)
    end

    def term(&block)
      @term_proc = block
    end

    def succ(&block)
      @succ_proc = block
    end

    def finale(&block)
      @finale_proc = block
    end

    def run(a, b)
      raise TermProcNotDefinedError unless @term_proc.is_a?(Proc)
      raise SuccProcNotDefinedError unless @succ_proc.is_a?(Proc)
      x = sum(@term_proc, a, @succ_proc, b)
      x = @finale_proc.call(x) if @finale_proc.is_a?(Proc)
      x
    end
  end

  def self.define(symbol, &block)
    o = @@defines[symbol] = Bleak.new
    yield o
    instance_eval <<-EOT
      def self.#{symbol}_sum(a, b)
        sum(#{symbol.inspect}, a, b)
      end
    EOT
  end

  def self.sum(symbol, a, b)
    @@defines[symbol].run(a, b)
  end
end

The definitions


			
Summer.define(:pi) do |pi|
  pi.term do |x|
    (1.0 / (x * (x + 2)))
  end

  pi.succ do |x|
    (x + 4)
  end

  pi.finale do |x|
    (x * 8)
  end
end

The executions


			
puts Summer.pi_sum(1, 1000)
puts Summer.sum(:pi, 1, 1000)