@@ -7,41 +7,64 @@ module Dependency
7
7
autoload :ModuleRelease , 'semantic/dependency/module_release'
8
8
autoload :Source , 'semantic/dependency/source'
9
9
10
+ # @!group Sources
11
+
12
+ # @return [Array<Source>] a frozen copy of the {Source} list
10
13
def sources
11
14
( @sources ||= [ ] ) . dup . freeze
12
15
end
13
16
17
+ # Appends a new {Source} to the current list.
18
+ # @param source [Source] the {Source} to add
19
+ # @return [void]
14
20
def add_source ( source )
15
21
sources
16
22
@sources << source
23
+ nil
17
24
end
18
25
26
+ # Clears the current list of {Source}s.
27
+ # @return [void]
19
28
def clear_sources
20
29
sources
21
30
@sources . clear
31
+ nil
22
32
end
23
33
34
+ # @!endgroup
35
+
24
36
# Fetches a graph of modules and their dependencies from the currently
25
37
# configured list of {Source}s.
26
38
#
27
- # @param modules [{ String => String }]
39
+ # @todo Return a specialized "Graph" object.
40
+ # @todo Allow for external constraints to be added to the graph.
28
41
# @see #sources
29
42
# @see #add_source
30
43
# @see #clear_sources
44
+ #
45
+ # @param modules [{ String => String }]
46
+ # @return [ModuleRelease] the root of a dependency graph
31
47
def query ( modules )
32
- release = Source ::ROOT_CAUSE . create_release ( '' , nil , modules )
48
+ graph = Source ::ROOT_CAUSE . create_release ( '' , nil , modules )
33
49
34
- modules = fetch release
35
- releases = modules . values . flatten << release
50
+ modules = fetch ( graph )
51
+ releases = modules . values . flatten << graph
36
52
releases . each do |rel |
37
53
rel . dependencies . each do |name |
38
- rel . satisfy_dependencies modules [ name ]
54
+ rel . satisfy_dependencies ( modules [ name ] )
39
55
end
40
56
end
41
57
42
- return release
58
+ return graph
43
59
end
44
60
61
+ # Given a graph result from {#query}, this method will resolve the graph of
62
+ # dependencies, if possible, into a flat list of the best suited modules. If
63
+ # the dependency graph does not have a suitable resolution, this method will
64
+ # raise an exception to that effect.
65
+ #
66
+ # @param graph [ModuleRelease] the root of a dependency graph
67
+ # @return [Array<ModuleRelease>] the list of releases to act on
45
68
def resolve ( graph )
46
69
catch :next do
47
70
return walk ( graph . depends_on )
@@ -56,9 +79,11 @@ def resolve(graph)
56
79
# placed on it, being {ModuleRelease#satisfied? satisfied}, and having the
57
80
# greatest version number (with stability being preferred over prereleases).
58
81
#
59
- # @param dependencies [{ String => Array(ModuleRelease) }] the dependencies
60
- # @param considering [Array(ModuleRelease)] the set of releases being tested
61
- # @return [Array(ModuleRelease)] the list of releases to use, if successful
82
+ # @todo Traversal order is not presently guaranteed.
83
+ #
84
+ # @param dependencies [{ String => Array<ModuleRelease> }] the dependencies
85
+ # @param considering [Array<ModuleRelease>] the set of releases being tested
86
+ # @return [Array<ModuleRelease>] the list of releases to use, if successful
62
87
def walk ( dependencies , *considering )
63
88
return considering if dependencies . empty?
64
89
@@ -80,7 +105,7 @@ def walk(dependencies, *considering)
80
105
# will return a completed dependency list. If there were problems
81
106
# resolving our dependencies, we'll catch `:next`, which will cause
82
107
# us to move to the next possibility.
83
- return walk ( merged , dep , *considering )
108
+ return walk ( merged , *considering , dep )
84
109
end
85
110
end
86
111
@@ -90,15 +115,20 @@ def walk(dependencies, *considering)
90
115
throw :next
91
116
end
92
117
93
- # @param module [ModuleRelease] the release to detail
118
+ # Given a {ModuleRelease}, this method will iterate through the current
119
+ # list of {Source}s to find the complete list of versions available for its
120
+ # dependencies.
121
+ #
122
+ # @param release [ModuleRelease] the release to fetch details for
123
+ # @return [{ String => [ModuleRelease] }] the fetched dependency information
94
124
def fetch ( release , cache = Hash . new { |h , k | h [ k ] = { } } )
95
125
release . dependencies . each do |mod |
96
126
next if cache . key? mod
97
127
releases = cache [ mod ]
98
128
sources . each do |source |
99
129
source . fetch ( mod ) . each do |dependency |
100
130
releases [ dependency . version ] ||= dependency
101
- fetch dependency , cache
131
+ fetch ( dependency , cache )
102
132
end
103
133
end
104
134
end
@@ -108,13 +138,19 @@ def fetch(release, cache = Hash.new { |h,k| h[k] = {} })
108
138
end
109
139
end
110
140
141
+ # Given a list of potential releases, this method returns the most suitable
142
+ # releases for exploration. Only {ModuleRelease#satisfied? satisfied}
143
+ # releases are considered, and releases with stable versions are preferred.
144
+ #
145
+ # @param releases [Array<ModuleRelease>] a list of potential releases
146
+ # @return [Array<ModuleRelease>] releases open for consideration
111
147
def preferred_releases ( releases )
112
- stable = proc { |x | x . version . prerelease . nil ? }
148
+ satisfied = releases . select { |x | x . satisfied ? }
113
149
114
- if releases . none? ( & stable )
115
- return releases . select { |r | r . satisfied ? }
150
+ if satisfied . any? { | x | x . version . stable? }
151
+ return satisfied . select { |x | x . version . stable ? }
116
152
else
117
- return releases . select ( & stable ) . select { | r | r . satisfied? }
153
+ return satisfied
118
154
end
119
155
end
120
156
end
0 commit comments