1module Rake
2
3  ####################################################################
4  # InvocationChain tracks the chain of task invocations to detect
5  # circular dependencies.
6  class InvocationChain
7    def initialize(value, tail)
8      @value = value
9      @tail = tail
10    end
11
12    def member?(obj)
13      @value == obj || @tail.member?(obj)
14    end
15
16    def append(value)
17      if member?(value)
18        fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
19      end
20      self.class.new(value, self)
21    end
22
23    def to_s
24      "#{prefix}#{@value}"
25    end
26
27    def self.append(value, chain)
28      chain.append(value)
29    end
30
31    private
32
33    def prefix
34      "#{@tail.to_s} => "
35    end
36
37    class EmptyInvocationChain
38      def member?(obj)
39        false
40      end
41      def append(value)
42        InvocationChain.new(value, self)
43      end
44      def to_s
45        "TOP"
46      end
47    end
48
49    EMPTY = EmptyInvocationChain.new
50  end
51end
52