versus 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.index +45 -0
- data/.yardopts +7 -0
- data/HISTORY.md +11 -0
- data/Index.yml +37 -0
- data/LICENSE.txt +23 -0
- data/README.md +46 -0
- data/demo/applique/ae.rb +5 -0
- data/demo/applique/main.rb +1 -0
- data/demo/constraint/02_initialize.md +44 -0
- data/demo/constraint/04_to_proc.md +11 -0
- data/demo/constraint/09_to_gem_version.md +10 -0
- data/demo/number/02_initialize.md +14 -0
- data/demo/number/03_parse.md +23 -0
- data/demo/number/04_crush.md +17 -0
- data/demo/number/05_build.md +23 -0
- data/demo/number/06_cmp.md +100 -0
- data/demo/number/07_segments.md +51 -0
- data/demo/number/08_bump.md +46 -0
- data/demo/number/09_stable_release.md +23 -0
- data/demo/number/10_prerelease.md +19 -0
- data/demo/number/11_release_candidate.md +15 -0
- data/demo/number/19_match.md +10 -0
- data/demo/number/20_to_str.md +13 -0
- data/demo/resolver/01_initialize.md +23 -0
- data/demo/resolver/02_add.md +11 -0
- data/demo/resolver/03_libraries.md +24 -0
- data/demo/resolver/04_requirements.md +13 -0
- data/demo/resolver/05_possibilities.md +13 -0
- data/demo/resolver/06_resolve.md +42 -0
- data/lib/versus.rb +5 -0
- data/lib/versus/constraint.rb +130 -0
- data/lib/versus/core_ext.rb +4 -0
- data/lib/versus/core_ext/array.rb +11 -0
- data/lib/versus/core_ext/kernel.rb +19 -0
- data/lib/versus/core_ext/string.rb +10 -0
- data/lib/versus/exceptions.rb +8 -0
- data/lib/versus/file.rb +157 -0
- data/lib/versus/file/jeweler_format.rb +49 -0
- data/lib/versus/file/plain_format.rb +39 -0
- data/lib/versus/number.rb +516 -0
- data/lib/versus/resolver.rb +303 -0
- metadata +124 -0
@@ -0,0 +1,303 @@
|
|
1
|
+
module Version
|
2
|
+
|
3
|
+
# Version resolution takes a requirements list and can reduce it
|
4
|
+
# to a best fit list.
|
5
|
+
#
|
6
|
+
class Resolver
|
7
|
+
|
8
|
+
#
|
9
|
+
#
|
10
|
+
#
|
11
|
+
def initialize(*available)
|
12
|
+
@libraries = Hash.new{ |h,k| h[k] = {} }
|
13
|
+
|
14
|
+
available.each do |name, version, requirements|
|
15
|
+
add(name, version, requirements || {})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Map of dependencies by name and version to requirements.
|
21
|
+
#
|
22
|
+
attr :libraries
|
23
|
+
|
24
|
+
#
|
25
|
+
# Add available library.
|
26
|
+
#
|
27
|
+
def add(name, version, requirements={})
|
28
|
+
name = name.to_s
|
29
|
+
number = Number.parse(version)
|
30
|
+
requires = {}
|
31
|
+
|
32
|
+
requirements.each do |n,c|
|
33
|
+
requires[n.to_s] = Constraint.parse(c)
|
34
|
+
end
|
35
|
+
|
36
|
+
@libraries[name][number] = requires
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Look-up requirements for a given name and version.
|
41
|
+
#
|
42
|
+
def requirements(name, number)
|
43
|
+
number = Version::Number.parse(number) #unless Version::Number === number
|
44
|
+
@libraries[name][number]
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Returns possibilities sorted in descending order.
|
49
|
+
#
|
50
|
+
def possibilities(name, constraint)
|
51
|
+
name = name.to_s
|
52
|
+
constraint = Constraint.parse(constraint)
|
53
|
+
|
54
|
+
list = []
|
55
|
+
@libraries[name].each do |version, _|
|
56
|
+
if constraint.match?(version)
|
57
|
+
list << [name, version]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
list.sort!{ |a,b| b[1] <=> a[1] }
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# TODO: support resolution of multiple [name, versions] at once.
|
66
|
+
#
|
67
|
+
def resolve(name, number)
|
68
|
+
name = name.to_s
|
69
|
+
number = Number.parse(number)
|
70
|
+
|
71
|
+
sheet = {}
|
72
|
+
|
73
|
+
result = resolve_(name, number, sheet)
|
74
|
+
|
75
|
+
#list.each do |name, version|
|
76
|
+
# name = name.to_s
|
77
|
+
# number = Number.parse(version)
|
78
|
+
#
|
79
|
+
# resolve_(name, number, sheet)
|
80
|
+
#end
|
81
|
+
result ? sheet : nil
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
#
|
87
|
+
#
|
88
|
+
#
|
89
|
+
def resolve_(name, number, sheet={})
|
90
|
+
return false unless settle(name, number, sheet)
|
91
|
+
|
92
|
+
potents = requirements(name, number).map do |(n, c)|
|
93
|
+
possibilities(n,c)
|
94
|
+
end
|
95
|
+
|
96
|
+
return sheet if potents.empty?
|
97
|
+
|
98
|
+
vectors = product(*potents)
|
99
|
+
|
100
|
+
success = vectors.find do |vector|
|
101
|
+
resolve_vector(vector, sheet)
|
102
|
+
end
|
103
|
+
|
104
|
+
return success
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
#
|
109
|
+
#
|
110
|
+
def resolve_vector(vector, sheet)
|
111
|
+
vector.each do |(n,v)|
|
112
|
+
r = resolve_(n, v, sheet)
|
113
|
+
return false unless r
|
114
|
+
end
|
115
|
+
return sheet
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
#
|
120
|
+
#
|
121
|
+
def settle(name, number, sheet={})
|
122
|
+
if sheet[name]
|
123
|
+
return false if sheet[name] != number
|
124
|
+
else
|
125
|
+
sheet[name] = number
|
126
|
+
end
|
127
|
+
return true
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
#
|
132
|
+
#
|
133
|
+
def product(*list)
|
134
|
+
return [] if list.empty?
|
135
|
+
head, *rest = *list
|
136
|
+
head.product(*rest)
|
137
|
+
end
|
138
|
+
|
139
|
+
=begin
|
140
|
+
#
|
141
|
+
#
|
142
|
+
#
|
143
|
+
def collect_possibilites
|
144
|
+
possibilites = Hash.new{ |h,k| h[k] = Hash.new{|h2,k2| h2[k2] = [] } }
|
145
|
+
constrained_versions = collect_constraints
|
146
|
+
libraries.each do |name, version, requirements|
|
147
|
+
requirements.each do |(n,c)|
|
148
|
+
possibilites[[name, version]][n] << constrained_versions[[n,c]]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
possibilites
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Iterate over all requirements and collect all possible versions
|
156
|
+
# that fit their constraints.
|
157
|
+
#
|
158
|
+
def collect_constraints
|
159
|
+
constraints = {}
|
160
|
+
@libraries.each do |name, version, requirements|
|
161
|
+
requirements.each do |n,c|
|
162
|
+
next if constraints[[n,c]]
|
163
|
+
constraints[[n,c]] = matching_versions(n,c)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
constraints
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
#
|
171
|
+
#
|
172
|
+
def matching_versions(name, constraint)
|
173
|
+
vers = @versions[name].select{ |v| constraint.fits?(v) }.sort
|
174
|
+
vers.map{ |v| [name, v] }
|
175
|
+
end
|
176
|
+
=end
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
=begin
|
181
|
+
# Resolve dependencies for given list of name-version.
|
182
|
+
#
|
183
|
+
# @param [Array] list
|
184
|
+
#
|
185
|
+
def resolve(list)
|
186
|
+
requirements = collect_requirements(list)
|
187
|
+
|
188
|
+
# time to do some backtracking
|
189
|
+
first, *rest = *requirements.values
|
190
|
+
first.product(*rest).find |possibility|
|
191
|
+
valid?(possibility)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Collect requirements for given set of desired entries.
|
197
|
+
#
|
198
|
+
# TODO: Reduce requirements for same names
|
199
|
+
#
|
200
|
+
def collect_requirements(list)
|
201
|
+
requirements = {}
|
202
|
+
list.each do |(name, version)|
|
203
|
+
if @requirements.key?([name,version])
|
204
|
+
@requirements[[name,version]].each do |(n,c)|
|
205
|
+
next if requirements[[n,c]]
|
206
|
+
requirements[[n,c]] = matching_versions(n,c)
|
207
|
+
end
|
208
|
+
else
|
209
|
+
raise "no resolution - no available entry for #{name}-#{verison}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
requirements
|
213
|
+
end
|
214
|
+
|
215
|
+
#
|
216
|
+
#
|
217
|
+
#
|
218
|
+
def resolve_
|
219
|
+
reqs = {}
|
220
|
+
constraints.each do |name, *cons|
|
221
|
+
reqs[name] = reduce(*cons)
|
222
|
+
end
|
223
|
+
reqs
|
224
|
+
end
|
225
|
+
|
226
|
+
#
|
227
|
+
#
|
228
|
+
#
|
229
|
+
def constraints(list)
|
230
|
+
cons = {}
|
231
|
+
list.each do |(name, constraint)|
|
232
|
+
cons[name.to_s] ||= []
|
233
|
+
cons[name.to_s] << Constraint.parse(constraint)
|
234
|
+
end
|
235
|
+
cons
|
236
|
+
end
|
237
|
+
=end
|
238
|
+
|
239
|
+
#
|
240
|
+
#
|
241
|
+
#
|
242
|
+
def reduce(*constraints)
|
243
|
+
exact, least, most = nil , nil, nil
|
244
|
+
|
245
|
+
constraints.each do |c|
|
246
|
+
case c.op
|
247
|
+
when '==', '='
|
248
|
+
if exact
|
249
|
+
if exact != c.number
|
250
|
+
exact, least, most = nil, nil, nil
|
251
|
+
break
|
252
|
+
end
|
253
|
+
else
|
254
|
+
exact = c
|
255
|
+
end
|
256
|
+
when '<'
|
257
|
+
if least
|
258
|
+
if c.number <= least.number
|
259
|
+
least = c
|
260
|
+
end
|
261
|
+
else
|
262
|
+
least = c
|
263
|
+
end
|
264
|
+
when '>'
|
265
|
+
if most
|
266
|
+
if c.number >= most.number
|
267
|
+
most = c
|
268
|
+
end
|
269
|
+
else
|
270
|
+
most = c
|
271
|
+
end
|
272
|
+
when '<='
|
273
|
+
if least
|
274
|
+
if c.number < least.number
|
275
|
+
least = c
|
276
|
+
end
|
277
|
+
else
|
278
|
+
least = c
|
279
|
+
end
|
280
|
+
when '>='
|
281
|
+
if most
|
282
|
+
if c.number > most.number
|
283
|
+
most = c
|
284
|
+
end
|
285
|
+
else
|
286
|
+
most = c
|
287
|
+
end
|
288
|
+
when '=~'
|
289
|
+
# TODO
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# there be only one!
|
294
|
+
return nil if exact && least
|
295
|
+
return nil if exact && most
|
296
|
+
return nil if least && most
|
297
|
+
|
298
|
+
exact || least || most
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: versus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- trans
|
9
|
+
- postmodern
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-01-05 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: qed
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: ae
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
description: The Versus gem provides a solid Version class along with supporting functionality,
|
48
|
+
such as version constratints and version dependency resolution.
|
49
|
+
email:
|
50
|
+
- transfire@gmail.com
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files:
|
54
|
+
- LICENSE.txt
|
55
|
+
- HISTORY.md
|
56
|
+
- README.md
|
57
|
+
files:
|
58
|
+
- .index
|
59
|
+
- .yardopts
|
60
|
+
- demo/number/04_crush.md
|
61
|
+
- demo/number/02_initialize.md
|
62
|
+
- demo/number/09_stable_release.md
|
63
|
+
- demo/number/03_parse.md
|
64
|
+
- demo/number/20_to_str.md
|
65
|
+
- demo/number/10_prerelease.md
|
66
|
+
- demo/number/05_build.md
|
67
|
+
- demo/number/19_match.md
|
68
|
+
- demo/number/06_cmp.md
|
69
|
+
- demo/number/08_bump.md
|
70
|
+
- demo/number/07_segments.md
|
71
|
+
- demo/number/11_release_candidate.md
|
72
|
+
- demo/applique/main.rb
|
73
|
+
- demo/applique/ae.rb
|
74
|
+
- demo/resolver/06_resolve.md
|
75
|
+
- demo/resolver/04_requirements.md
|
76
|
+
- demo/resolver/02_add.md
|
77
|
+
- demo/resolver/03_libraries.md
|
78
|
+
- demo/resolver/05_possibilities.md
|
79
|
+
- demo/resolver/01_initialize.md
|
80
|
+
- demo/constraint/04_to_proc.md
|
81
|
+
- demo/constraint/02_initialize.md
|
82
|
+
- demo/constraint/09_to_gem_version.md
|
83
|
+
- lib/versus.rb
|
84
|
+
- lib/versus/file.rb
|
85
|
+
- lib/versus/exceptions.rb
|
86
|
+
- lib/versus/constraint.rb
|
87
|
+
- lib/versus/core_ext/array.rb
|
88
|
+
- lib/versus/core_ext/kernel.rb
|
89
|
+
- lib/versus/core_ext/string.rb
|
90
|
+
- lib/versus/file/jeweler_format.rb
|
91
|
+
- lib/versus/file/plain_format.rb
|
92
|
+
- lib/versus/resolver.rb
|
93
|
+
- lib/versus/core_ext.rb
|
94
|
+
- lib/versus/number.rb
|
95
|
+
- LICENSE.txt
|
96
|
+
- Index.yml
|
97
|
+
- HISTORY.md
|
98
|
+
- README.md
|
99
|
+
homepage: http://dotruby.github.com
|
100
|
+
licenses:
|
101
|
+
- BSD-2-Clause
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.8.23
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Best-of-breed Version Class Library
|
124
|
+
test_files: []
|