# frozen_string_literal: true module Core module Event # [public] Compiles an event pipeline into evalable code. # class Compiler class << self # [public] Compiles an event pipeline. # def compile(pipeline) validate_events(pipeline) <<~CODE def performing(object, event, ...) #{compile_performing(pipeline)} end def starting(object, event, ...) #{compile_starting(pipeline)} end def finished(object, event, ...) #{compile_finished(pipeline)} end CODE end private def validate_events(pipeline) diff = pipeline.pipelines.keys - pipeline.events if diff.any? diff_string = diff.map { |event| "`#{event}`" }.join(", ") raise "cannot define callbacks for the following unknown events: #{diff_string}" end end private def compile_performing(pipeline) compiled = +"" pipeline.pipelines.each_pair do |event, pipelines| before = pipelines[:before] during = pipelines[:during] after = pipelines[:after] if before.any? || during.any? || after.any? compiled << "when #{event.inspect}\n" compiled << "if block_given?\n" compiled << " call_callbacks(object, :before, event, ...)\n" if before.any? compiled << " call_callbacks(object, :during, event, ...)\n" if during.any? compiled << " yield\n" compiled << " call_callbacks(object, :after, event, ...)\n" if after.any? compiled << "else\n" compiled << " call_callbacks(object, :during, event, ...)\n" if during.any? compiled << "end\n" end end if compiled.empty? <<~CODE validate_event(event.to_sym) yield if block_given? CODE else <<~CODE event = event.to_sym case event #{compiled} else validate_event(event) end CODE end end private def compile_starting(pipeline) compiled = +"" pipeline.pipelines.each_pair do |event, pipelines| before = pipelines[:before] if before.any? compiled << "when #{event.inspect}\n" compiled << "call_callbacks(object, :before, event, ...)\n" end end if compiled.empty? <<~CODE validate_event(event.to_sym) CODE else <<~CODE event = event.to_sym case event #{compiled} else validate_event(event) end CODE end end private def compile_finished(pipeline) compiled = +"" pipeline.pipelines.each_pair do |event, pipelines| after = pipelines[:after] if after.any? compiled << "when #{event.inspect}\n" compiled << "call_callbacks(object, :after, event, ...)\n" end end if compiled.empty? <<~CODE validate_event(event.to_sym) CODE else <<~CODE event = event.to_sym case event #{compiled} else validate_event(event) end CODE end end end end end end