card/lib/card/director/run.rb
class Card
class Director
# methods for running stages
module Run
def catch_up_to_stage next_stage
return if @delay && before?(:integrate_with_delay, next_stage)
upto_stage(next_stage) do |stage|
run_stage stage
end
end
def run_delayed_event act
@running = true
@act = act
@current_stage_index = stage_index :integrate_with_delay
yield
run_subcard_stages :integrate_with_delay
end
def delay!
@delay = true
end
def restart
@running = false
@current_stage_index = nil
end
private
def run_stage stage, &block
return true unless valid_next_stage? stage
# puts "#{@card.name}: #{stage} stage".yellow
@current_stage_index = stage_index stage
handle_stage stage, block do
run_stage_callbacks stage
run_subcard_stages stage
run_final_stage_callbacks stage
end
end
def handle_stage stage, block
case stage
when :initialize
prepare_for_phases
when :store
# in the store stage it can be necessary that
# other subcards must be saved before we save this card
return store(&block)
end
yield
end
def run_stage_callbacks stage, callback_postfix=""
Rails.logger.debug "#{stage}: #{@card.name}"
# we use abort :success in the :store stage for :save_draft
callbacks = :"#{stage}#{callback_postfix}_stage"
if in_or_before?(:store, stage) && !main?
@card.abortable { @card.run_callbacks callbacks }
else
@card.run_callbacks callbacks
end
end
def run_subcard_stages stage
each_subcard_director stage do |subdir|
condition = block_given? ? yield(subdir) : true
subdir.catch_up_to_stage stage if condition
end
end
def each_subcard_director stage
subdirectors.each do |subdir|
yield subdir unless subdir.head? && before?(:integrate, stage)
end
ensure
@card.handle_subcard_errors
end
def run_final_stage_callbacks stage
run_stage_callbacks stage, "_final"
end
def upto_stage stage
@current_stage_index ||= -1
(@current_stage_index + 1).upto(stage_index(stage)) do |i|
yield stage_symbol(i)
end
end
def valid_next_stage? next_stage
@current_stage_index ||= -1
return false if @abort ||
in_or_after?(next_stage) ||
ahead_of_parent?(next_stage) ||
!valid_card?(next_stage)
check_skipped_stage next_stage
true
end
def valid_card? next_stage
@card.errors.empty? || in_or_before?(:validate, next_stage)
end
def check_skipped_stage stage
return unless before? previous_stage_index(stage)
raise Card::Error, "stage #{previous_stage_symbol stage} was " \
"skipped for card #{@card}"
end
def ahead_of_parent? next_stage
head? ? false : after?(parent.current_stage_index, next_stage)
end
end
end
end