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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
# frozen_string_literal: true
require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular'
require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex'
require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named'
require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload'
require 'rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag'
module Gem::Resolver::Molinillo
class DependencyGraph
# A log for dependency graph actions
class Log
# Initializes an empty log
def initialize
@current_action = @first_action = nil
end
# @!macro [new] action
# {include:DependencyGraph#$0}
# @param [Graph] graph the graph to perform the action on
# @param (see DependencyGraph#$0)
# @return (see DependencyGraph#$0)
# @macro action
def tag(graph, tag)
push_action(graph, Tag.new(tag))
end
# @macro action
def add_vertex(graph, name, payload, root)
push_action(graph, AddVertex.new(name, payload, root))
end
# @macro action
def detach_vertex_named(graph, name)
push_action(graph, DetachVertexNamed.new(name))
end
# @macro action
def add_edge_no_circular(graph, origin, destination, requirement)
push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
end
# @macro action
def set_payload(graph, name, payload)
push_action(graph, SetPayload.new(name, payload))
end
# Pops the most recent action from the log and undoes the action
# @param [DependencyGraph] graph
# @return [Action] the action that was popped off the log
def pop!(graph)
return unless action = @current_action
unless @current_action = action.previous
@first_action = nil
end
action.down(graph)
action
end
extend Enumerable
# @!visibility private
# Enumerates each action in the log
# @yield [Action]
def each
return enum_for unless block_given?
action = @first_action
loop do
break unless action
yield action
action = action.next
end
self
end
# @!visibility private
# Enumerates each action in the log in reverse order
# @yield [Action]
def reverse_each
return enum_for(:reverse_each) unless block_given?
action = @current_action
loop do
break unless action
yield action
action = action.previous
end
self
end
# @macro action
def rewind_to(graph, tag)
loop do
action = pop!(graph)
raise "No tag #{tag.inspect} found" unless action
break if action.class.name == :tag && action.tag == tag
end
end
private
# Adds the given action to the log, running the action
# @param [DependencyGraph] graph
# @param [Action] action
# @return The value returned by `action.up`
def push_action(graph, action)
action.previous = @current_action
@current_action.next = action if @current_action
@current_action = action
@first_action ||= action
action.up(graph)
end
end
end
end
|