module Temple::Mixins::CompiledDispatcher

def call(exp)

def call(exp)
  compile(exp)
end

def case_statement(types)

def case_statement(types)
  code = "type, *args = args\ncase type\n"
  types.each do |name, method|
    code << "when #{name.to_sym.inspect}\n" <<
      (Hash === method ? case_statement(method) : "#{method}(*args)\n")
  end
  code << "else\nexp\nend\n"
end

def compile(exp)

def compile(exp)
  dispatcher(exp)
end

def dispatcher(exp)

def dispatcher(exp)
  replace_dispatcher(exp)
end

def replace_dispatcher(exp)

def replace_dispatcher(exp)
  types = {}
  self.class.instance_methods.each do |method|
    next if method.to_s !~ /^on_(.*)$/
    method_types = $1.split('_')
    (0...method_types.size).inject(types) do |tmp, i|
      raise "Invalid temple dispatcher #{method}" unless Hash === tmp
      if i == method_types.size - 1
        tmp[method_types[i]] = method
      else
        tmp[method_types[i]] ||= {}
      end
    end
  end
  self.class.class_eval %{
    def dispatcher(exp)
      if self.class == #{self.class}
        args = exp
        #{case_statement(types)}
      else
        replace_dispatcher(exp)
      end
    end
  }
  dispatcher(exp)
end