summaryrefslogtreecommitdiff
path: root/lib/rake/invocation_chain.rb
blob: 540628957c1ea6d65550b2c3f9f157697fcbb7c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
module Rake

  # InvocationChain tracks the chain of task invocations to detect
  # circular dependencies.
  class InvocationChain < LinkedList

    # Is the invocation already in the chain?
    def member?(invocation)
      head == invocation || tail.member?(invocation)
    end

    # Append an invocation to the chain of invocations. It is an error
    # if the invocation already listed.
    def append(invocation)
      if member?(invocation)
        fail RuntimeError, "Circular dependency detected: #{to_s} => #{invocation}"
      end
      conj(invocation)
    end

    # Convert to string, ie: TOP => invocation => invocation
    def to_s
      "#{prefix}#{head}"
    end

    # Class level append.
    def self.append(invocation, chain)
      chain.append(invocation)
    end

    private

    def prefix
      "#{tail} => "
    end

    # Null object for an empty chain.
    class EmptyInvocationChain < LinkedList::EmptyLinkedList
      @parent = InvocationChain

      def member?(obj)
        false
      end

      def append(invocation)
        conj(invocation)
      end

      def to_s
        "TOP"
      end
    end

    EMPTY = EmptyInvocationChain.new
  end
end