solve 0.3.1 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  script: "bundle exec thor spec"
2
2
  language: ruby
3
+ bundler_args: --without development
3
4
  rvm:
4
5
  - 1.9.2
5
6
  - 1.9.3
data/Gemfile CHANGED
@@ -1,3 +1,46 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ group :development do
6
+ gem 'pry'
7
+ gem 'fuubar'
8
+ gem 'yard'
9
+ gem 'redcarpet'
10
+ gem 'guard'
11
+ gem 'guard-rspec'
12
+ gem 'guard-spork'
13
+ gem 'guard-yard'
14
+
15
+ platform :ruby_19 do
16
+ gem 'coolline'
17
+ end
18
+
19
+ require 'rbconfig'
20
+
21
+ if RbConfig::CONFIG['target_os'] =~ /darwin/i
22
+ gem 'growl', require: false
23
+ gem 'rb-fsevent', require: false
24
+
25
+ if `uname`.strip == 'Darwin' && `sw_vers -productVersion`.strip >= '10.8'
26
+ gem 'terminal-notifier-guard', '~> 1.5.3', require: false
27
+ end rescue Errno::ENOENT
28
+
29
+ elsif RbConfig::CONFIG['target_os'] =~ /linux/i
30
+ gem 'libnotify', '~> 0.7.1', require: false
31
+ gem 'rb-inotify', require: false
32
+
33
+ elsif RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
34
+ gem 'win32console', require: false
35
+ gem 'rb-notifu', '>= 0.0.4', require: false
36
+ gem 'wdm', require: false
37
+ end
38
+ end
39
+
40
+ group :test do
41
+ gem 'thor', '>= 0.16.0'
42
+ gem 'rake', '>= 0.9.2.2'
43
+
44
+ gem 'spork'
45
+ gem 'rspec'
46
+ end
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Dependency Status](https://gemnasium.com/reset/solve.png?travis)](https://gemnasium.com/reset/solve)
4
4
  [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/reset/solve)
5
5
 
6
- A Ruby constraint solver
6
+ A Ruby versioning constraint solver implementing [Semantic Versioning 2.0.0-rc.1](http://semver.org).
7
7
 
8
8
  ## Installation
9
9
 
@@ -21,7 +21,7 @@ Add an artifact to the graph
21
21
 
22
22
  Now add another artifact that has a dependency
23
23
 
24
- graph.artifacts("mysql", "1.2.4").depends("openssl", "~> 1.0.0")
24
+ graph.artifacts("mysql", "1.2.4-alpha.1").depends("openssl", "~> 1.0.0")
25
25
 
26
26
  Dependencies can be chained, too
27
27
 
@@ -40,5 +40,8 @@ And now solve the graph with some demands
40
40
  ## Authors
41
41
 
42
42
  Author:: Jamie Winsor (<jamie@vialstudios.com>)
43
+ Author:: Andrew Garson (<andrew.garson@gmail.com>)
43
44
 
44
- Copyright 2012 Jamie Winsor
45
+ ## Contributors
46
+
47
+ [Thibaud Guillaume-Gentil](https://github.com/thibaudgg) ([@thibaudgg](http://twitter.com/thibaudgg))
@@ -1,5 +1,6 @@
1
1
  module Solve
2
2
  # @author Jamie Winsor <jamie@vialstudios.com>
3
+ # @author Thibaud Guillaume-Gentil <thibaud@thibaud.me>
3
4
  class Constraint
4
5
  class << self
5
6
  # Split a constraint string into an Array of two elements. The first
@@ -81,32 +82,42 @@ module Solve
81
82
  #
82
83
  # @return [Boolean]
83
84
  def compare_aprox(constraint, target_version)
84
- unless constraint.patch.nil?
85
- target_version.patch >= constraint.patch &&
86
- target_version.minor == constraint.minor &&
87
- target_version.major == constraint.major
85
+ min = constraint.version
86
+ if constraint.patch == nil
87
+ max = Version.new([min.major + 1, 0, 0, 0])
88
+ elsif constraint.build
89
+ identifiers = constraint.version.identifiers(:build)
90
+ replace = identifiers.last.to_i.to_s == identifiers.last.to_s ? "-" : nil
91
+ max = Version.new([min.major, min.minor, min.patch, min.pre_release, identifiers.fill(replace, -1).join('.')])
92
+ elsif constraint.pre_release
93
+ identifiers = constraint.version.identifiers(:pre_release)
94
+ replace = identifiers.last.to_i.to_s == identifiers.last.to_s ? "-" : nil
95
+ max = Version.new([min.major, min.minor, min.patch, identifiers.fill(replace, -1).join('.')])
88
96
  else
89
- target_version.minor >= constraint.minor &&
90
- target_version.major == constraint.major
97
+ max = Version.new([min.major, min.minor + 1, 0, 0])
91
98
  end
99
+ min <= target_version && target_version < max
92
100
  end
93
101
  end
94
102
 
95
103
  OPERATORS = {
96
- "=" => method(:compare_equal),
97
- ">" => method(:compare_gt),
98
- "<" => method(:compare_lt),
104
+ "~>" => method(:compare_aprox),
99
105
  ">=" => method(:compare_gte),
100
106
  "<=" => method(:compare_lte),
101
- "~>" => method(:compare_aprox)
107
+ "=" => method(:compare_equal),
108
+ "~" => method(:compare_aprox),
109
+ ">" => method(:compare_gt),
110
+ "<" => method(:compare_lt)
102
111
  }.freeze
103
112
 
104
- REGEXP = /^(#{OPERATORS.keys.join('|')}) (.+)$/
113
+ REGEXP = /^(#{OPERATORS.keys.join('|')})\s?(.+)$/
105
114
 
106
115
  attr_reader :operator
107
116
  attr_reader :major
108
117
  attr_reader :minor
109
118
  attr_reader :patch
119
+ attr_reader :pre_release
120
+ attr_reader :build
110
121
 
111
122
  # @param [#to_s] constraint
112
123
  def initialize(constraint = ">= 0.0.0")
@@ -115,7 +126,7 @@ module Solve
115
126
  raise Errors::InvalidConstraintFormat.new(constraint)
116
127
  end
117
128
 
118
- @major, @minor, @patch = Version.split(ver_str)
129
+ @major, @minor, @patch, @pre_release, @build = Version.split(ver_str)
119
130
  @compare_fun = OPERATORS.fetch(self.operator)
120
131
  end
121
132
 
@@ -124,7 +135,15 @@ module Solve
124
135
  #
125
136
  # @return [Solve::Version]
126
137
  def version
127
- @version ||= Version.new([self.major, self.minor, self.patch])
138
+ @version ||= Version.new(
139
+ [
140
+ self.major,
141
+ self.minor,
142
+ self.patch,
143
+ self.pre_release,
144
+ self.build
145
+ ]
146
+ )
128
147
  end
129
148
 
130
149
  # Returns true or false if the given version would be satisfied by
@@ -145,12 +164,16 @@ module Solve
145
164
  def ==(other)
146
165
  other.is_a?(self.class) &&
147
166
  self.operator == other.operator &&
148
- self.version == other.version
167
+ self.version == other.version
149
168
  end
150
169
  alias_method :eql?, :==
151
170
 
152
171
  def to_s
153
- "#{operator} #{major}.#{minor}.#{patch}"
172
+ str = operator
173
+ str += " #{major}.#{minor}.#{patch}"
174
+ str += "-#{pre_release}" if pre_release
175
+ str += "+#{build}" if build
176
+ str
154
177
  end
155
178
  end
156
179
  end
@@ -1,3 +1,3 @@
1
1
  module Solve
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0.rc1"
3
3
  end
data/lib/solve/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Solve
2
2
  # @author Jamie Winsor <jamie@vialstudios.com>
3
+ # @author Thibaud Guillaume-Gentil <thibaud@thibaud.me>
3
4
  class Version
4
5
  class << self
5
6
  # @param [#to_s] version_string
@@ -8,11 +9,15 @@ module Solve
8
9
  #
9
10
  # @return [Array]
10
11
  def split(version_string)
11
- major, minor, patch = case version_string.to_s
12
+ case version_string.to_s
13
+ when /^(\d+)\.(\d+)\.(\d+)(-([0-9a-z\-\.]+))?(\+([0-9a-z\-\.]+))?$/i
14
+ [ $1.to_i, $2.to_i, $3.to_i, $5, $7 ]
12
15
  when /^(\d+)\.(\d+)\.(\d+)$/
13
16
  [ $1.to_i, $2.to_i, $3.to_i ]
14
17
  when /^(\d+)\.(\d+)$/
15
18
  [ $1.to_i, $2.to_i, nil ]
19
+ when /^(\d+)$/
20
+ [ $1.to_i, nil, nil ]
16
21
  else
17
22
  raise Errors::InvalidVersionFormat.new(version_string)
18
23
  end
@@ -24,30 +29,32 @@ module Solve
24
29
  attr_reader :major
25
30
  attr_reader :minor
26
31
  attr_reader :patch
32
+ attr_reader :pre_release
33
+ attr_reader :build
27
34
 
28
35
  # @overload initialize(version_array)
29
36
  # @param [Array] version_array
30
37
  #
31
38
  # @example
32
- # Version.new([1, 2, 3]) => #<Version: @major=1, @minor=2, @patch=3>
39
+ # Version.new([1, 2, 3, 'rc.1', 'build.1']) => #<Version: @major=1, @minor=2, @patch=3, @pre_release='rc.1', @build='build.1'>
33
40
  #
34
41
  # @overload initialize(version_string)
35
42
  # @param [#to_s] version_string
36
43
  #
37
44
  # @example
38
- # Version.new("1.2.3") => #<Version: @major=1, @minor=2, @patch=3>
45
+ # Version.new("1.2.3-rc.1+build.1") => #<Version: @major=1, @minor=2, @patch=3, @pre_release='rc.1', @build='build.1'>
39
46
  #
40
47
  # @overload initialize(version)
41
48
  # @param [Solve::Version] version
42
49
  #
43
50
  # @example
44
- # Version.new(Version.new("1.2.3")) => #<Version: @major=1, @minor=2, @patch=3>
51
+ # Version.new(Version.new("1.2.3-rc.1+build.1")) => #<Version: @major=1, @minor=2, @pre_release='rc.1', @build='build.1'>
45
52
  #
46
53
  def initialize(*args)
47
54
  if args.first.is_a?(Array)
48
- @major, @minor, @patch = args.first
55
+ @major, @minor, @patch, @pre_release, @build = args.first
49
56
  else
50
- @major, @minor, @patch = self.class.split(args.first.to_s)
57
+ @major, @minor, @patch, @pre_release, @build = self.class.split(args.first.to_s)
51
58
  end
52
59
 
53
60
  @major ||= 0
@@ -59,10 +66,48 @@ module Solve
59
66
  #
60
67
  # @return [Integer]
61
68
  def <=>(other)
62
- [:major, :minor, :patch].each do |method|
63
- ans = (self.send(method) <=> other.send(method))
69
+ [:major, :minor, :patch].each do |release|
70
+ ans = self.send(release) <=> other.send(release)
64
71
  return ans if ans != 0
65
72
  end
73
+ ans = pre_release_and_build_presence_score <=> other.pre_release_and_build_presence_score
74
+ return ans if ans != 0
75
+ ans = identifiers_comparaison(other, :pre_release)
76
+ return ans if ans != 0
77
+ if build && other.build
78
+ return identifiers_comparaison(other, :build)
79
+ else
80
+ return build.to_s <=> other.build.to_s
81
+ end
82
+ 0
83
+ end
84
+
85
+ # @return [Array]
86
+ def identifiers(release)
87
+ send(release).to_s.split('.').map do |str|
88
+ str.to_i.to_s == str ? str.to_i : str
89
+ end
90
+ end
91
+
92
+ # @return [Integer]
93
+ def pre_release_and_build_presence_score
94
+ pre_release ? 0 : (build.nil? ? 1 : 2)
95
+ end
96
+
97
+ # @param [Solve::Version] other
98
+ #
99
+ # @return [Integer]
100
+ def identifiers_comparaison(other, release)
101
+ [identifiers(release).length, other.identifiers(release).length].max.times do |i|
102
+ if identifiers(release)[i].class == other.identifiers(release)[i].class
103
+ ans = identifiers(release)[i] <=> other.identifiers(release)[i]
104
+ return ans if ans != 0
105
+ elsif identifiers(release)[i] && other.identifiers(release)[i]
106
+ return identifiers(release)[i].class.to_s <=> other.identifiers(release)[i].class.to_s
107
+ elsif identifiers(release)[i] || other.identifiers(release)[i]
108
+ return other.identifiers(release)[i].class.to_s <=> identifiers(release)[i].class.to_s
109
+ end
110
+ end
66
111
  0
67
112
  end
68
113
 
@@ -78,7 +123,10 @@ module Solve
78
123
  end
79
124
 
80
125
  def to_s
81
- "#{major}.#{minor}.#{patch}"
126
+ str = "#{major}.#{minor}.#{patch}"
127
+ str += "-#{pre_release}" if pre_release
128
+ str += "+#{build}" if build
129
+ str
82
130
  end
83
131
  end
84
132
  end
data/solve.gemspec CHANGED
@@ -2,12 +2,12 @@
2
2
  require File.expand_path('../lib/solve/gem_version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.authors = ["Jamie Winsor", "Andrew Garson"]
6
- s.email = ["jamie@vialstudios.com", "andrew.garson@gmail.com"]
7
- s.description = %q{A Ruby constraint solver}
8
- s.summary = s.description
5
+ s.authors = ["Jamie Winsor", "Andrew Garson", "Thibaud Guillaume-Gentil"]
6
+ s.email = ["jamie@vialstudios.com", "andrew.garson@gmail.com", "thibaud@thibaud.me"]
7
+ s.description = %q{A Ruby version constraint solver}
8
+ s.summary = %q{A Ruby version constraint solver implementing Semantic Versioning 2.0.0-rc.1}
9
9
  s.homepage = "https://github.com/reset/solve"
10
-
10
+
11
11
  s.files = `git ls-files`.split($\)
12
12
  s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
13
  s.test_files = s.files.grep(%r{^spec/})
@@ -17,18 +17,4 @@ Gem::Specification.new do |s|
17
17
  s.required_ruby_version = ">= 1.9.1"
18
18
 
19
19
  s.add_dependency 'json'
20
-
21
- s.add_development_dependency 'thor', '>= 0.16.0'
22
- s.add_development_dependency 'rake', '>= 0.9.2.2'
23
- s.add_development_dependency 'pry'
24
- s.add_development_dependency 'rspec'
25
- s.add_development_dependency 'fuubar'
26
- s.add_development_dependency 'spork'
27
- s.add_development_dependency 'yard'
28
- s.add_development_dependency 'redcarpet'
29
- s.add_development_dependency 'guard'
30
- s.add_development_dependency 'guard-rspec'
31
- s.add_development_dependency 'guard-spork'
32
- s.add_development_dependency 'guard-yard'
33
- s.add_development_dependency 'coolline'
34
20
  end
@@ -1,5 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
+ RSpec::Matchers.define :satisfies do |*args|
4
+ match do |constraint|
5
+ constraint.satisfies?(*args).should be_true
6
+ end
7
+ end
8
+
3
9
  describe Solve::Constraint do
4
10
  let(:valid_string) { ">= 0.0.0" }
5
11
  let(:invalid_string) { "x23u7089213.*" }
@@ -16,6 +22,10 @@ describe Solve::Constraint do
16
22
  subject.new(valid_string).operator.should eql(">=")
17
23
  end
18
24
 
25
+ it "assigns the parsed operator to the operator attribute with no separation between operator and version" do
26
+ subject.new(">=0.0.0").operator.should eql(">=")
27
+ end
28
+
19
29
  it "assigns the parsed version string as an instance of Version to the version attribute" do
20
30
  result = subject.new(valid_string)
21
31
 
@@ -73,133 +83,176 @@ describe Solve::Constraint do
73
83
  end
74
84
  end
75
85
 
76
- describe "#satisfies?" do
86
+ describe "#satisfies?", :focus do
77
87
  subject { Solve::Constraint.new("= 1.0.0") }
78
88
 
79
- it "accepts a String for version" do
80
- subject.satisfies?("1.0.0").should be_true
81
- end
89
+ it { should satisfies("1.0.0") }
82
90
 
83
91
  it "accepts a Version for version" do
84
- subject.satisfies?(Solve::Version.new("1.0.0")).should be_true
92
+ should satisfies(Solve::Version.new("1.0.0"))
85
93
  end
86
94
 
87
95
  context "strictly greater than (>)" do
88
- subject { Solve::Constraint.new("> 1.0.0") }
89
-
90
- it "returns true if the given version would satisfy the constraint" do
91
- subject.satisfies?("2.0.0").should be_true
92
- end
96
+ subject { Solve::Constraint.new("> 1.0.0-alpha") }
93
97
 
94
- it "returns false if the given version would not satisfy the constraint" do
95
- subject.satisfies?("1.0.0").should be_false
96
- end
98
+ it { should satisfies("2.0.0") }
99
+ it { should satisfies("1.0.0") }
100
+ it { should_not satisfies("1.0.0-alpha") }
97
101
  end
98
102
 
99
103
  context "strictly less than (<)" do
100
- subject { Solve::Constraint.new("< 1.0.0") }
101
-
102
- it "returns true if the given version would satisfy the constraint" do
103
- subject.satisfies?("0.1.0").should be_true
104
- end
104
+ subject { Solve::Constraint.new("< 1.0.0+build.20") }
105
105
 
106
- it "returns false if the given version would not satisfy the constraint" do
107
- subject.satisfies?("1.0.0").should be_false
108
- end
106
+ it { should satisfies("0.1.0") }
107
+ it { should satisfies("1.0.0") }
108
+ it { should_not satisfies("1.0.0+build.21") }
109
109
  end
110
110
 
111
111
  context "strictly equal to (=)" do
112
112
  subject { Solve::Constraint.new("= 1.0.0") }
113
113
 
114
- it "returns true if the given version would satisfy the constraint" do
115
- subject.satisfies?("1.0.0").should be_true
116
- end
117
-
118
- it "returns false if the given version would not satisfy the constraint" do
119
- subject.satisfies?("1.0.1").should be_false
120
- end
114
+ it { should_not satisfies("0.9.9+build") }
115
+ it { should satisfies("1.0.0") }
116
+ it { should_not satisfies("1.0.1") }
117
+ it { should_not satisfies("1.0.0-alpha") }
121
118
  end
122
119
 
123
120
  context "greater than or equal to (>=)" do
124
121
  subject { Solve::Constraint.new(">= 1.0.0") }
125
122
 
126
- it "returns true if the given version is greater than the version constraint" do
127
- subject.satisfies?("2.0.0").should be_true
128
- end
129
-
130
- it "returns true if the given version is equal to the version constraint" do
131
- subject.satisfies?("1.0.0").should be_true
132
- end
133
-
134
- it "returns false if the given version is less than the version constraint" do
135
- subject.satisfies?("0.9.0").should be_false
136
- end
123
+ it { should_not satisfies("0.9.9+build") }
124
+ it { should_not satisfies("1.0.0-alpha") }
125
+ it { should satisfies("1.0.0") }
126
+ it { should satisfies("1.0.1") }
127
+ it { should satisfies("2.0.0") }
137
128
  end
138
129
 
139
130
  context "greater than or equal to (<=)" do
140
131
  subject { Solve::Constraint.new("<= 1.0.0") }
141
132
 
142
- it "returns true if the given version is less than the version constraint" do
143
- subject.satisfies?("0.9.0").should be_true
144
- end
145
-
146
- it "returns true if the given version is equal to the version constraint" do
147
- subject.satisfies?("1.0.0").should be_true
148
- end
149
-
150
- it "returns false if the given version is less than the version constraint" do
151
- subject.satisfies?("1.0.1").should be_false
152
- end
133
+ it { should satisfies("0.9.9+build") }
134
+ it { should satisfies("1.0.0-alpha") }
135
+ it { should satisfies("1.0.0") }
136
+ it { should_not satisfies("1.0.0+build") }
137
+ it { should_not satisfies("1.0.1") }
138
+ it { should_not satisfies("2.0.0") }
153
139
  end
154
140
 
155
- context "aproximately (~>)" do
156
- subject { Solve::Constraint.new("~> 1.0.0") }
157
-
158
- it "returns true if the given version is equal to the version constraint" do
159
- subject.satisfies?("1.0.0").should be_true
160
- end
161
-
162
- context "when the last value in the constraint is for patch" do
163
- subject { Solve::Constraint.new("~> 1.0.1") }
164
-
165
- it "returns true if the patch level is greater than the constraint's" do
166
- subject.satisfies?("1.0.2").should be_true
141
+ %w[~> ~].each do |operator|
142
+ describe "aproximately (#{operator})" do
143
+ context "when the last value in the constraint is for minor" do
144
+ subject { Solve::Constraint.new("#{operator} 1.2") }
145
+
146
+ it { should_not satisfies("1.1.0") }
147
+ it { should_not satisfies("1.2.0-alpha") }
148
+ it { should satisfies("1.2.0") }
149
+ it { should satisfies("1.2.3") }
150
+ it { should satisfies("1.2.3+build") }
151
+ it { should_not satisfies("2.0.0-0") }
152
+ it { should_not satisfies("2.0.0") }
167
153
  end
168
154
 
169
- it "returns true if the patch level is equal to the constraint's" do
170
- subject.satisfies?("1.0.1").should be_true
171
- end
155
+ context "when the last value in the constraint is for minor" do
156
+ subject { Solve::Constraint.new("#{operator} 1.2.3") }
172
157
 
173
- it "returns false if the patch level is less than the constraint's" do
174
- subject.satisfies?("1.0.0").should be_false
158
+ it { should_not satisfies("1.1.0") }
159
+ it { should_not satisfies("1.2.3-alpha") }
160
+ it { should_not satisfies("1.2.2") }
161
+ it { should satisfies("1.2.3") }
162
+ it { should satisfies("1.2.5+build") }
163
+ it { should_not satisfies("1.3.0-0") }
164
+ it { should_not satisfies("1.3.0") }
175
165
  end
176
166
 
177
- it "returns false if the given version is less than the constraint's" do
178
- subject.satisfies?("0.9.0").should be_false
167
+ context "when the last value in the constraint is for pre_release with a last numeric identifier" do
168
+ subject { Solve::Constraint.new("#{operator} 1.2.3-4") }
169
+
170
+ it { should_not satisfies("1.2.3") }
171
+ it { should satisfies("1.2.3-4") }
172
+ it { should satisfies("1.2.3-10") }
173
+ it { should satisfies("1.2.3-10.5+build.33") }
174
+ it { should_not satisfies("1.2.3--") }
175
+ it { should_not satisfies("1.2.3-alpha") }
176
+ it { should_not satisfies("1.2.3") }
177
+ it { should_not satisfies("1.2.4") }
178
+ it { should_not satisfies("1.3.0") }
179
179
  end
180
- end
181
-
182
- context "when the last value in the constraint is for minor" do
183
- subject { Solve::Constraint.new("~> 1.1") }
184
180
 
185
- it "returns true if the minor level is greater than the constraint's" do
186
- subject.satisfies?("1.2").should be_true
181
+ context "when the last value in the constraint is for pre_release with a last non-numeric identifier" do
182
+ subject { Solve::Constraint.new("#{operator} 1.2.3-alpha") }
183
+
184
+ it { should_not satisfies("1.2.3-4") }
185
+ it { should_not satisfies("1.2.3--") }
186
+ it { should satisfies("1.2.3-alpha") }
187
+ it { should satisfies("1.2.3-alpha.0") }
188
+ it { should satisfies("1.2.3-beta") }
189
+ it { should satisfies("1.2.3-omega") }
190
+ it { should satisfies("1.2.3-omega.4") }
191
+ it { should_not satisfies("1.2.3") }
192
+ it { should_not satisfies("1.3.0") }
187
193
  end
188
194
 
189
- it "returns true if the minor level is equal to the constraint's" do
190
- subject.satisfies?("1.1").should be_true
195
+ context "when the last value in the constraint is for build with a last numeric identifier and a pre-release" do
196
+ subject { Solve::Constraint.new("#{operator} 1.2.3-alpha+5") }
197
+
198
+ it { should_not satisfies("1.2.3-alpha") }
199
+ it { should_not satisfies("1.2.3-alpha.4") }
200
+ it { should_not satisfies("1.2.3-alpha.4+4") }
201
+ it { should satisfies("1.2.3-alpha+5") }
202
+ it { should satisfies("1.2.3-alpha+5.5") }
203
+ it { should satisfies("1.2.3-alpha+10") }
204
+ it { should_not satisfies("1.2.3-alpha+-") }
205
+ it { should_not satisfies("1.2.3-alpha+build") }
206
+ it { should_not satisfies("1.2.3-beta") }
207
+ it { should_not satisfies("1.2.3") }
208
+ it { should_not satisfies("1.3.0") }
191
209
  end
192
210
 
193
- it "returns true if a patch level is set but the minor level is equal to or greater than the constraint's" do
194
- subject.satisfies?("1.2.8").should be_true
211
+ context "when the last value in the constraint is for build with a last non-numeric identifier and a pre-release" do
212
+ subject { Solve::Constraint.new("#{operator} 1.2.3-alpha+build") }
213
+
214
+ it { should_not satisfies("1.2.3-alpha") }
215
+ it { should_not satisfies("1.2.3-alpha.4") }
216
+ it { should_not satisfies("1.2.3-alpha.4+4") }
217
+ it { should satisfies("1.2.3-alpha+build") }
218
+ it { should satisfies("1.2.3-alpha+build.5") }
219
+ it { should satisfies("1.2.3-alpha+preview") }
220
+ it { should satisfies("1.2.3-alpha+zzz") }
221
+ it { should_not satisfies("1.2.3-alphb") }
222
+ it { should_not satisfies("1.2.3-beta") }
223
+ it { should_not satisfies("1.2.3") }
224
+ it { should_not satisfies("1.3.0") }
195
225
  end
196
226
 
197
- it "returns false if the patch level is less than the constraint's" do
198
- subject.satisfies?("1.0.1").should be_false
227
+ context "when the last value in the constraint is for build with a last numeric identifier" do
228
+ subject { Solve::Constraint.new("#{operator} 1.2.3+5") }
229
+
230
+ it { should_not satisfies("1.2.3") }
231
+ it { should_not satisfies("1.2.3-alpha") }
232
+ it { should_not satisfies("1.2.3+4") }
233
+ it { should satisfies("1.2.3+5") }
234
+ it { should satisfies("1.2.3+99") }
235
+ it { should_not satisfies("1.2.3+5.build") }
236
+ it { should_not satisfies("1.2.3+-") }
237
+ it { should_not satisfies("1.2.3+build") }
238
+ it { should_not satisfies("1.2.4") }
239
+ it { should_not satisfies("1.3.0") }
199
240
  end
200
241
 
201
- it "returns false if the major level is greater than the constraint's" do
202
- subject.satisfies?("2.0.0").should be_false
242
+ context "when the last value in the constraint is for build with a last non-numeric identifier" do
243
+ subject { Solve::Constraint.new("#{operator} 1.2.3+build") }
244
+
245
+ it { should_not satisfies("1.2.3-alpha") }
246
+ it { should_not satisfies("1.2.3") }
247
+ it { should_not satisfies("1.2.3+5") }
248
+ it { should satisfies("1.2.3+build") }
249
+ it { should satisfies("1.2.3+build.5") }
250
+ it { should satisfies("1.2.3+preview") }
251
+ it { should satisfies("1.2.3+zzz") }
252
+ it { should_not satisfies("1.2.4-0") }
253
+ it { should_not satisfies("1.2.4") }
254
+ it { should_not satisfies("1.2.5") }
255
+ it { should_not satisfies("1.3.0") }
203
256
  end
204
257
  end
205
258
  end
@@ -5,6 +5,54 @@ describe Solve::Version do
5
5
  subject { Solve::Version }
6
6
 
7
7
  describe "::new" do
8
+ context "a string containing a major, minor and patch separated by periods a pre-release and a build" do
9
+ before(:each) { @version = subject.new("1.2.3-rc.1+build.1") }
10
+
11
+ it "assigns a major value" do
12
+ @version.major.should eql(1)
13
+ end
14
+
15
+ it "assigns a minor value" do
16
+ @version.minor.should eql(2)
17
+ end
18
+
19
+ it "assigns a patch value" do
20
+ @version.patch.should eql(3)
21
+ end
22
+
23
+ it "assigns a pre_release value" do
24
+ @version.pre_release.should eql('rc.1')
25
+ end
26
+
27
+ it "assigns a build value" do
28
+ @version.build.should eql('build.1')
29
+ end
30
+ end
31
+
32
+ context "a string containing a major, minor and patch separated by periods and a build" do
33
+ before(:each) { @version = subject.new("1.2.3+pre-build.11.e0f985a") }
34
+
35
+ it "assigns a major value" do
36
+ @version.major.should eql(1)
37
+ end
38
+
39
+ it "assigns a minor value" do
40
+ @version.minor.should eql(2)
41
+ end
42
+
43
+ it "assigns a patch value" do
44
+ @version.patch.should eql(3)
45
+ end
46
+
47
+ it "doesn't assigns a pre_release value" do
48
+ @version.pre_release.should be_nil
49
+ end
50
+
51
+ it "assigns a build value" do
52
+ @version.build.should eql('pre-build.11.e0f985a')
53
+ end
54
+ end
55
+
8
56
  context "a string containing a major, minor, and patch separated by periods" do
9
57
  before(:each) { @version = subject.new("1.2.3") }
10
58
 
@@ -19,6 +67,62 @@ describe Solve::Version do
19
67
  it "assigns a patch value" do
20
68
  @version.patch.should eql(3)
21
69
  end
70
+
71
+ it "doesn't assigns a pre_release value" do
72
+ @version.pre_release.should be_nil
73
+ end
74
+
75
+ it "doesn't assigns a build value" do
76
+ @version.build.should be_nil
77
+ end
78
+ end
79
+
80
+ context "a five element array" do
81
+ before(:each) { @version = subject.new([1,2,3,nil,'build.1']) }
82
+
83
+ it "assigns a major value" do
84
+ @version.major.should eql(1)
85
+ end
86
+
87
+ it "assigns a minor value" do
88
+ @version.minor.should eql(2)
89
+ end
90
+
91
+ it "assigns a patch value" do
92
+ @version.patch.should eql(3)
93
+ end
94
+
95
+ it "doesn't assigns a pre_release value" do
96
+ @version.pre_release.should be_nil
97
+ end
98
+
99
+ it "assigns a build value" do
100
+ @version.build.should eql('build.1')
101
+ end
102
+ end
103
+
104
+ context "a four element array" do
105
+ before(:each) { @version = subject.new([1,2,3,'alpha.1']) }
106
+
107
+ it "assigns a major value" do
108
+ @version.major.should eql(1)
109
+ end
110
+
111
+ it "assigns a minor value" do
112
+ @version.minor.should eql(2)
113
+ end
114
+
115
+ it "assigns a patch value" do
116
+ @version.patch.should eql(3)
117
+ end
118
+
119
+ it "assigns a pre_release value" do
120
+ @version.pre_release.should eql('alpha.1')
121
+ end
122
+
123
+ it "doesn't assigns a build value" do
124
+ @version.build.should be_nil
125
+ end
22
126
  end
23
127
 
24
128
  context "a three element array" do
@@ -35,6 +139,14 @@ describe Solve::Version do
35
139
  it "assigns a patch value" do
36
140
  @version.patch.should eql(3)
37
141
  end
142
+
143
+ it "doesn't assigns a pre_release value" do
144
+ @version.pre_release.should be_nil
145
+ end
146
+
147
+ it "doesn't assigns a build value" do
148
+ @version.build.should be_nil
149
+ end
38
150
  end
39
151
 
40
152
  context "a two element array" do
@@ -51,6 +163,14 @@ describe Solve::Version do
51
163
  it "sets the patch value to 0 (zero)" do
52
164
  @version.patch.should eql(0)
53
165
  end
166
+
167
+ it "doesn't assigns a pre_release value" do
168
+ @version.pre_release.should be_nil
169
+ end
170
+
171
+ it "doesn't assigns a build value" do
172
+ @version.build.should be_nil
173
+ end
54
174
  end
55
175
 
56
176
  context "a one element array" do
@@ -66,7 +186,15 @@ describe Solve::Version do
66
186
 
67
187
  it "sets the patch value to 0 (zero)" do
68
188
  @version.patch.should eql(0)
69
- end
189
+ end
190
+
191
+ it "doesn't assigns a pre_release value" do
192
+ @version.pre_release.should be_nil
193
+ end
194
+
195
+ it "doesn't assigns a build value" do
196
+ @version.build.should be_nil
197
+ end
70
198
  end
71
199
 
72
200
  context "an empty array" do
@@ -83,16 +211,38 @@ describe Solve::Version do
83
211
  it "sets the patch value to 0 (zero)" do
84
212
  @version.patch.should eql(0)
85
213
  end
214
+
215
+ it "doesn't assigns a pre_release value" do
216
+ @version.pre_release.should be_nil
217
+ end
218
+
219
+ it "doesn't assigns a build value" do
220
+ @version.build.should be_nil
221
+ end
86
222
  end
87
223
  end
88
224
 
89
225
  describe "::split" do
90
- it "returns an array containing 3 elements" do
91
- subject.split("1.2.0").should have(3).items
226
+ it "returns an array containing 5 elements" do
227
+ subject.split("1.2.0-alpha.1").should have(5).items
228
+ end
229
+
230
+ context "given a string only containing a major, minor and patch version" do
231
+ it "returns an array containing 4 elements" do
232
+ subject.split("1.2.3").should have(5).items
233
+ end
234
+
235
+ it "returns nil as fourth element" do
236
+ subject.split("1.2.3")[3].should be_nil
237
+ end
238
+
239
+ it "returns nil as fifth element" do
240
+ subject.split("1.2.3")[4].should be_nil
241
+ end
92
242
  end
93
243
 
94
244
  context "given a string only containing a major and minor version" do
95
- it "returns an array containing 3 elements" do
245
+ it "returns an array containing 4 elements" do
96
246
  subject.split("1.2").should have(3).items
97
247
  end
98
248
 
@@ -102,20 +252,62 @@ describe Solve::Version do
102
252
  end
103
253
 
104
254
  context "given a string with only a major version" do
105
- it "raises an InvalidVersionFormat error" do
106
- lambda {
107
- subject.split("1")
108
- }.should raise_error(Solve::Errors::InvalidVersionFormat)
255
+ it "returns an array containing 3 elements" do
256
+ subject.split("1").should have(3).items
257
+ end
258
+
259
+ it "returns nil as the second element" do
260
+ subject.split("1")[2].should be_nil
261
+ end
262
+
263
+ it "returns nil as the third element" do
264
+ subject.split("1")[2].should be_nil
109
265
  end
110
266
  end
267
+
268
+ context "given a string with an invalid version"
269
+ it "raises an InvalidVersionFormat error" do
270
+ lambda {
271
+ subject.split("hello")
272
+ }.should raise_error(Solve::Errors::InvalidVersionFormat)
273
+ end
111
274
  end
112
275
  end
113
276
 
114
- subject { Solve::Version.new("1.0.0") }
115
-
116
277
  describe "#to_s" do
117
- it "returns a string containing the major.minor.patch" do
118
- subject.to_s.should eql("1.0.0")
278
+ subject { Solve::Version.new("1.0.0-rc.1+build.1") }
279
+
280
+ it "returns a string containing the major.minor.patch-pre_release+build" do
281
+ subject.to_s.should eql("1.0.0-rc.1+build.1")
119
282
  end
120
283
  end
284
+
285
+ describe "#<=>" do
286
+ it "compares versions" do
287
+ versions_list = %w[
288
+ 1.0.0-0
289
+ 1.0.0-alpha
290
+ 1.0.0-alpha.1
291
+ 1.0.0-beta.2
292
+ 1.0.0-beta.11
293
+ 1.0.0-rc.1
294
+ 1.0.0-rc.1+build.1
295
+ 1.0.0
296
+ 1.0.0+0.3.7
297
+ 1.0.0+build
298
+ 1.0.0+build.2.b8f12d7
299
+ 1.0.0+build.11.e0f985a
300
+ ]
301
+ versions = versions_list.map { |version| Solve::Version.new(version) }
302
+
303
+ 100.times do
304
+ shuffled_versions = versions.shuffle
305
+ while shuffled_versions == versions
306
+ shuffled_versions = shuffled_versions.shuffle
307
+ end
308
+ shuffled_versions.sort.map(&:to_s).should == versions_list
309
+ end
310
+ end
311
+ end
312
+
121
313
  end
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
5
- prerelease:
4
+ version: 0.4.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jamie Winsor
9
9
  - Andrew Garson
10
+ - Thibaud Guillaume-Gentil
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2012-09-29 00:00:00.000000000 Z
14
+ date: 2012-10-16 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: json
@@ -28,218 +29,11 @@ dependencies:
28
29
  - - ! '>='
29
30
  - !ruby/object:Gem::Version
30
31
  version: '0'
31
- - !ruby/object:Gem::Dependency
32
- name: thor
33
- requirement: !ruby/object:Gem::Requirement
34
- none: false
35
- requirements:
36
- - - ! '>='
37
- - !ruby/object:Gem::Version
38
- version: 0.16.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.16.0
47
- - !ruby/object:Gem::Dependency
48
- name: rake
49
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: 0.9.2.2
55
- type: :development
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: 0.9.2.2
63
- - !ruby/object:Gem::Dependency
64
- name: pry
65
- requirement: !ruby/object:Gem::Requirement
66
- none: false
67
- requirements:
68
- - - ! '>='
69
- - !ruby/object:Gem::Version
70
- version: '0'
71
- type: :development
72
- prerelease: false
73
- version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
- requirements:
76
- - - ! '>='
77
- - !ruby/object:Gem::Version
78
- version: '0'
79
- - !ruby/object:Gem::Dependency
80
- name: rspec
81
- requirement: !ruby/object:Gem::Requirement
82
- none: false
83
- requirements:
84
- - - ! '>='
85
- - !ruby/object:Gem::Version
86
- version: '0'
87
- type: :development
88
- prerelease: false
89
- version_requirements: !ruby/object:Gem::Requirement
90
- none: false
91
- requirements:
92
- - - ! '>='
93
- - !ruby/object:Gem::Version
94
- version: '0'
95
- - !ruby/object:Gem::Dependency
96
- name: fuubar
97
- requirement: !ruby/object:Gem::Requirement
98
- none: false
99
- requirements:
100
- - - ! '>='
101
- - !ruby/object:Gem::Version
102
- version: '0'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- none: false
107
- requirements:
108
- - - ! '>='
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: spork
113
- requirement: !ruby/object:Gem::Requirement
114
- none: false
115
- requirements:
116
- - - ! '>='
117
- - !ruby/object:Gem::Version
118
- version: '0'
119
- type: :development
120
- prerelease: false
121
- version_requirements: !ruby/object:Gem::Requirement
122
- none: false
123
- requirements:
124
- - - ! '>='
125
- - !ruby/object:Gem::Version
126
- version: '0'
127
- - !ruby/object:Gem::Dependency
128
- name: yard
129
- requirement: !ruby/object:Gem::Requirement
130
- none: false
131
- requirements:
132
- - - ! '>='
133
- - !ruby/object:Gem::Version
134
- version: '0'
135
- type: :development
136
- prerelease: false
137
- version_requirements: !ruby/object:Gem::Requirement
138
- none: false
139
- requirements:
140
- - - ! '>='
141
- - !ruby/object:Gem::Version
142
- version: '0'
143
- - !ruby/object:Gem::Dependency
144
- name: redcarpet
145
- requirement: !ruby/object:Gem::Requirement
146
- none: false
147
- requirements:
148
- - - ! '>='
149
- - !ruby/object:Gem::Version
150
- version: '0'
151
- type: :development
152
- prerelease: false
153
- version_requirements: !ruby/object:Gem::Requirement
154
- none: false
155
- requirements:
156
- - - ! '>='
157
- - !ruby/object:Gem::Version
158
- version: '0'
159
- - !ruby/object:Gem::Dependency
160
- name: guard
161
- requirement: !ruby/object:Gem::Requirement
162
- none: false
163
- requirements:
164
- - - ! '>='
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
- type: :development
168
- prerelease: false
169
- version_requirements: !ruby/object:Gem::Requirement
170
- none: false
171
- requirements:
172
- - - ! '>='
173
- - !ruby/object:Gem::Version
174
- version: '0'
175
- - !ruby/object:Gem::Dependency
176
- name: guard-rspec
177
- requirement: !ruby/object:Gem::Requirement
178
- none: false
179
- requirements:
180
- - - ! '>='
181
- - !ruby/object:Gem::Version
182
- version: '0'
183
- type: :development
184
- prerelease: false
185
- version_requirements: !ruby/object:Gem::Requirement
186
- none: false
187
- requirements:
188
- - - ! '>='
189
- - !ruby/object:Gem::Version
190
- version: '0'
191
- - !ruby/object:Gem::Dependency
192
- name: guard-spork
193
- requirement: !ruby/object:Gem::Requirement
194
- none: false
195
- requirements:
196
- - - ! '>='
197
- - !ruby/object:Gem::Version
198
- version: '0'
199
- type: :development
200
- prerelease: false
201
- version_requirements: !ruby/object:Gem::Requirement
202
- none: false
203
- requirements:
204
- - - ! '>='
205
- - !ruby/object:Gem::Version
206
- version: '0'
207
- - !ruby/object:Gem::Dependency
208
- name: guard-yard
209
- requirement: !ruby/object:Gem::Requirement
210
- none: false
211
- requirements:
212
- - - ! '>='
213
- - !ruby/object:Gem::Version
214
- version: '0'
215
- type: :development
216
- prerelease: false
217
- version_requirements: !ruby/object:Gem::Requirement
218
- none: false
219
- requirements:
220
- - - ! '>='
221
- - !ruby/object:Gem::Version
222
- version: '0'
223
- - !ruby/object:Gem::Dependency
224
- name: coolline
225
- requirement: !ruby/object:Gem::Requirement
226
- none: false
227
- requirements:
228
- - - ! '>='
229
- - !ruby/object:Gem::Version
230
- version: '0'
231
- type: :development
232
- prerelease: false
233
- version_requirements: !ruby/object:Gem::Requirement
234
- none: false
235
- requirements:
236
- - - ! '>='
237
- - !ruby/object:Gem::Version
238
- version: '0'
239
- description: A Ruby constraint solver
32
+ description: A Ruby version constraint solver
240
33
  email:
241
34
  - jamie@vialstudios.com
242
35
  - andrew.garson@gmail.com
36
+ - thibaud@thibaud.me
243
37
  executables: []
244
38
  extensions: []
245
39
  extra_rdoc_files: []
@@ -294,18 +88,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
294
88
  required_rubygems_version: !ruby/object:Gem::Requirement
295
89
  none: false
296
90
  requirements:
297
- - - ! '>='
91
+ - - ! '>'
298
92
  - !ruby/object:Gem::Version
299
- version: '0'
300
- segments:
301
- - 0
302
- hash: -267791564304481347
93
+ version: 1.3.1
303
94
  requirements: []
304
95
  rubyforge_project:
305
96
  rubygems_version: 1.8.23
306
97
  signing_key:
307
98
  specification_version: 3
308
- summary: A Ruby constraint solver
99
+ summary: A Ruby version constraint solver implementing Semantic Versioning 2.0.0-rc.1
309
100
  test_files:
310
101
  - spec/acceptance/solutions_spec.rb
311
102
  - spec/spec_helper.rb