Sha256: 21d0d45dc320ff84d81949ed7521456c40335a19d3f971424c5e45c3bd674a7d

Contents?: true

Size: 1.95 KB

Versions: 3

Compression:

Stored size: 1.95 KB

Contents

module Sprig
  class DependencySorter
    class CircularDependencyError < StandardError; end

    attr_reader :items

    def initialize(items)
      @items = items.to_a
    end

    def sorted_items
      sorted_tags.map do |tag|
        id_dictionary[tag]
      end
    end

    private

    def id_dictionary
      @id_dictionary ||= begin
        {}.tap do |hash|
          items.each do |item|
            hash[item.dependency_id] = item
          end
        end
      end
    end

    def dependency_hash
      @dependency_hash ||= begin
        TsortableHash.new.tap do |hash|
          items.each do |item|
            hash[item.dependency_id] = item.dependencies.map(&:id)
          end
        end
      end
    end

    def sorted_tags
      dependency_hash.tsort
    rescue TSort::Cyclic => e
      raise CircularDependencyError.new("Your sprig directives contain circular dependencies. #{e.message}")
    rescue KeyError => key_error
      raise missing_dependency_error_from_key_error(key_error)
    end

    def dependencies
      items.map(&:dependencies).flatten
    end

    def missing_dependency_error_from_key_error(key_error)
      key = key_error.message.match(/\Akey not found: "(.*)"\Z/)[1]
      missing_dependency = dependencies.detect { |item| item.id == key }
      MissingDependencyError.new(missing_dependency)
    end

    class TsortableHash < Hash
      include TSort

      alias tsort_each_node each_key

      def tsort_each_child(node, &block)
        fetch(node).each(&block)
      end
    end

    class MissingDependencyError < StandardError
      def initialize(missing_dependency = nil)
        super message_for(missing_dependency)
      end

      private

      def message_for(missing_dependency)
        if missing_dependency.is_a? Dependency
          "Undefined reference to '#{missing_dependency.sprig_record_reference}'"
        else
          "Referenced 'sprig_record' does not have a correlating record."
        end
      end
    end
  end
end

Version data entries

3 entries across 3 versions & 1 rubygems

Version Path
sprig-0.1.2 lib/sprig/dependency_sorter.rb
sprig-0.1.1 lib/sprig/dependency_sorter.rb
sprig-0.1.0 lib/sprig/dependency_sorter.rb