lib/temple/mixins/dispatcher.rb
module Temple module Mixins # @api private module CoreDispatcher def on_multi(*exps) multi = [:multi] exps.each {|exp| multi << compile(exp) } multi end def on_capture(name, exp) [:capture, name, compile(exp)] end end # @api private module EscapeDispatcher def on_escape(flag, exp) [:escape, flag, compile(exp)] end end # @api private module ControlFlowDispatcher def on_if(condition, *cases) [:if, condition, *cases.compact.map {|e| compile(e) }] end def on_case(arg, *cases) [:case, arg, *cases.map {|condition, exp| [condition, compile(exp)] }] end def on_block(code, content) [:block, code, compile(content)] end def on_cond(*cases) [:cond, *cases.map {|condition, exp| [condition, compile(exp)] }] end end # @api private module CompiledDispatcher def call(exp) compile(exp) end def compile(exp) dispatcher(exp) end private 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 dispatcher(exp) replace_dispatcher(exp) end 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 end # @api private module Dispatcher include CompiledDispatcher include CoreDispatcher include EscapeDispatcher include ControlFlowDispatcher end end end