solve 0.3.1 → 0.4.0.rc1

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/.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