<commit_before>require "action/plan/version"
require "action/state"

module Action
  class Plan
    def initialize
      @schedule = []
      yield DSL.new(self) if block_given?
    end

    def run
      schedule.each do |state|
        action = state.create_action(plan: self)
        run_action action, state
        break unless state.status == :done
      end
    end

    def run_action action, state
      state.status = :running
      action.run
      state.status = :done
    rescue
      state.status = :failed
    end

    def action_states
      schedule.dup
    end

    def status
      case
      when schedule.empty?
        :empty
      when schedule.all? { |state| state.status == :planned }
        :planned
      when schedule.all? { |state| state.status == :done }
        :done
      when schedule.any? { |state| state.status == :failed }
        :failed
      when schedule.any? { |state| state.status == :running }
        :running
      else
        :invalid
      end
    end

    # let action plan itself
    def plan_action action_class, &block
      action_class.new(plan: self, &block).plan
      self
    end

    # schedule action execution at the current point in the plan
    def schedule_action action_class, config
      new_state = Action::State.new(action_class: action_class, config: config)
      schedule << new_state
      new_state.status = :planned
      self
    end

    class DSL<commit_msg>more correct plan status validator<commit_after>require "action/plan/version"
require "action/state"

module Action
  class Plan
    def initialize
      @schedule = []
      yield DSL.new(self) if block_given?
    end

    def run
      schedule.each do |state|
        action = state.create_action(plan: self)
        run_action action, state
        break unless state.status == :done
      end
    end

    def run_action action, state
      state.status = :running
      action.run
      state.status = :done
    rescue
      state.status = :failed
    end

    def action_states
      schedule.dup
    end

    def status
      chunks = schedule.map(&:status).chunk{|status|status}
      statuses = chunks.map(&:first)
      chunks = chunks.map(&:last)
      current = nil
      case chunks.count
      when 0
        return :empty
      when 1
        status = statuses.first
        return status if [:done, :planned].include?(status)
        current = 0
      when 2
        current = if statuses.first == :done
                    1
                  elsif statuses.last == :planned
                    0
                  end
      when 3
        current = 1 if statuses.first == :done && statuses.last == :planned
      end
      if current
        status = statuses[current]
        if [:failed, :running].include?(status) && chunks[current].length == 1
          return status
        end
      end
      :invalid
    end

    # let action plan itself
    def plan_action action_class, &block
      action_class.new(plan: self, &block).plan
      self
    end

    # schedule action execution at the current point in the plan
    def schedule_action action_class, config
      new_state = Action::State.new(action_class: action_class, config: config)
      schedule << new_state
      new_state.status = :planned
      self
    end

    class DSL
{'fraction_non_alphanumeric': 0.08004851425106124, 'fraction_numerical': 0.0027289266221952697, 'mean_word_length': 1.9693969396939695, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4467821', 'n_tokens_mistral': 943, 'n_tokens_neox': 909, 'n_words': 281}