summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPan Thomakos <pan.thomakos@gmail.com>2015-04-16 23:00:29 -0700
committerPan Thomakos <pan.thomakos@gmail.com>2015-04-17 08:37:14 -0700
commit2c8dd13c5617e402caebc0c113abc53cf8f4df58 (patch)
tree4b66bf34349dd33aecbe4243089e402a5f98a8d5
parentc7fce7422f467407f7544062661cbbb726b9ef38 (diff)
downloadbundler-2c8dd13c5617e402caebc0c113abc53cf8f4df58.tar.gz
Allow fuzzy ruby version requirements.
* Use `Gem::Requirement` and `Gem::Version` to parse and check ruby version, engine_version and patchlevel requirements. * Added new class `RubyVersionRequirement` to handle this functionality. * Added tests that cover the `RubyVersionRequirement` class.
-rw-r--r--CHANGELOG.md6
-rw-r--r--lib/bundler.rb1
-rw-r--r--lib/bundler/definition.rb8
-rw-r--r--lib/bundler/ruby_dsl.rb2
-rw-r--r--lib/bundler/ruby_version.rb48
-rw-r--r--spec/bundler/ruby_version_spec.rb80
-rw-r--r--spec/other/platform_spec.rb26
7 files changed, 118 insertions, 53 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 64d7542a5f..33ec3a5f55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Next Release
+
+Features:
+
+ - Allow fuzzy ruby version, patchlevel and engine version requirements (#70, @panthomakos)
+
## 1.9.4 (2015-04-13)
Bugfixes:
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 49d9fd6883..7fcc07d1eb 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -44,6 +44,7 @@ module Bundler
autoload :SourceList, 'bundler/source_list'
autoload :Specification, 'bundler/shared_helpers'
autoload :SystemRubyVersion, 'bundler/ruby_version'
+ autoload :RubyVersionRequirement,'bundler/ruby_version'
autoload :UI, 'bundler/ui'
class BundlerError < StandardError
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 9643144427..d36e56a86e 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -42,7 +42,7 @@ module Bundler
# @param sources [Bundler::SourceList]
# @param unlock [Hash, Boolean, nil] Gems that have been requested
# to be updated or true if all gems should be updated
- # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
+ # @param ruby_version [Bundler::RubyVersionRequirement, nil] Requested Ruby Version
# @param optional_groups [Array(String)] A list of optional groups
def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [])
@unlocking = unlock == true || !unlock.empty?
@@ -386,11 +386,7 @@ module Bundler
when :engine_version
"Your #{Bundler.ruby_version.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
when :patchlevel
- if !expected.is_a?(String)
- "The Ruby patchlevel in your Gemfile must be a string"
- else
- "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
- end
+ "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
end
raise RubyVersionMismatch, msg
diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb
index b29fc019a7..c1f83d3ad7 100644
--- a/lib/bundler/ruby_dsl.rb
+++ b/lib/bundler/ruby_dsl.rb
@@ -5,7 +5,7 @@ module Bundler
raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
raise GemfileError, "ruby_version must match the :engine_version for MRI" if options[:engine] == "ruby" && options[:engine_version] && ruby_version != options[:engine_version]
- @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
+ @ruby_version = RubyVersionRequirement.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
end
end
end
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index da6ebae080..224a5ec60e 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -38,26 +38,6 @@ module Bundler
patchlevel == other.patchlevel
end
- # Returns a tuple of these things:
- # [diff, this, other]
- # The priority of attributes are
- # 1. engine
- # 2. ruby_version
- # 3. engine_version
- def diff(other)
- if engine != other.engine && @input_engine
- [ :engine, engine, other.engine ]
- elsif version != other.version
- [ :version, version, other.version ]
- elsif engine_version != other.engine_version && @input_engine
- [ :engine_version, engine_version, other.engine_version ]
- elsif patchlevel != other.patchlevel && @patchlevel
- [ :patchlevel, patchlevel, other.patchlevel ]
- else
- nil
- end
- end
-
def host
@host ||= [
RbConfig::CONFIG["host_cpu"],
@@ -114,4 +94,32 @@ module Bundler
RUBY_PATCHLEVEL.to_s
end
end
+
+ class RubyVersionRequirement < RubyVersion
+ # Returns a tuple of these things:
+ # [diff, this, other]
+ # The priority of attributes are
+ # 1. engine
+ # 2. ruby_version
+ # 3. engine_version
+ def diff(other)
+ if engine != other.engine && @input_engine
+ [ :engine, engine, other.engine ]
+ elsif !version || !matches?(version, other.version)
+ [ :version, version, other.version ]
+ elsif @input_engine && !matches?(engine_version, other.engine_version)
+ [ :engine_version, engine_version, other.engine_version ]
+ elsif @patchlevel && !matches?(patchlevel, other.patchlevel)
+ [ :patchlevel, patchlevel, other.patchlevel ]
+ else
+ nil
+ end
+ end
+
+ private
+
+ def matches?(requirement, version)
+ Gem::Requirement.create(requirement).satisfied_by?(Gem::Version.new(version))
+ end
+ end
end
diff --git a/spec/bundler/ruby_version_spec.rb b/spec/bundler/ruby_version_spec.rb
new file mode 100644
index 0000000000..32d52cbfe4
--- /dev/null
+++ b/spec/bundler/ruby_version_spec.rb
@@ -0,0 +1,80 @@
+require "spec_helper"
+require "bundler/ruby_version"
+
+describe Bundler::RubyVersion do
+ def requirement(version, patchlevel=nil, engine=nil, engine_version=nil)
+ Bundler::RubyVersionRequirement.new(
+ version, patchlevel, engine, engine_version)
+ end
+
+ def version(version, patchlevel=nil, engine=nil, engine_version=nil)
+ Bundler::RubyVersion.new(version, patchlevel, engine, engine_version)
+ end
+
+ it "matches simple version requirements" do
+ expect(requirement("2.0.0").diff(version("2.0.0"))).to be_nil
+ end
+
+ it "matches simple patchlevel requirements" do
+ req = requirement("2.0.0", "645")
+ ver = version("2.0.0", "645")
+
+ expect(req.diff(ver)).to be_nil
+ end
+
+ it "matches engine" do
+ req = requirement("2.0.0", "645", "ruby")
+ ver = version("2.0.0", "645", "ruby")
+
+ expect(req.diff(ver)).to be_nil
+ end
+
+ it "matches simple engine version requirements" do
+ req = requirement("2.0.0", "645", "ruby", "2.0.1")
+ ver = version("2.0.0", "645", "ruby", "2.0.1")
+
+ expect(req.diff(ver)).to be_nil
+ end
+
+ it "detects engine discrepancies first" do
+ req = requirement("2.0.0", "645", "ruby", "2.0.1")
+ ver = requirement("2.0.1", "643", "rbx", "2.0.0")
+
+ expect(req.diff(ver)).to eq([:engine, "ruby", "rbx"])
+ end
+
+ it "detects version discrepancies second" do
+ req = requirement("2.0.0", "645", "ruby", "2.0.1")
+ ver = requirement("2.0.1", "643", "ruby", "2.0.0")
+
+ expect(req.diff(ver)).to eq([:version, "2.0.0", "2.0.1"])
+ end
+
+ it "detects engine version discrepancies third" do
+ req = requirement("2.0.0", "645", "ruby", "2.0.1")
+ ver = requirement("2.0.0", "643", "ruby", "2.0.0")
+
+ expect(req.diff(ver)).to eq([:engine_version, "2.0.1", "2.0.0"])
+ end
+
+ it "detects patchlevel discrepancies last" do
+ req = requirement("2.0.0", "645", "ruby", "2.0.1")
+ ver = requirement("2.0.0", "643", "ruby", "2.0.1")
+
+ expect(req.diff(ver)).to eq([:patchlevel, "645", "643"])
+ end
+
+ it "successfully matches gem requirements" do
+ req = requirement(">= 2.0.0", "< 643", "ruby", "~> 2.0.1")
+ ver = version("2.0.0", "642", "ruby", "2.0.5")
+
+ expect(req.diff(ver)).to be_nil
+ end
+
+ it "successfully detects bad gem requirements" do
+ req = requirement(">= 2.0.0", "< 643", "ruby", "~> 2.0.1")
+ ver = version("2.0.0", "642", "ruby", "2.1.0")
+
+ expect(req.diff(ver)).to eq([:engine_version, "~> 2.0.1", "2.1.0"])
+ end
+end
diff --git a/spec/other/platform_spec.rb b/spec/other/platform_spec.rb
index ad9390cfa8..2c161f9e4b 100644
--- a/spec/other/platform_spec.rb
+++ b/spec/other/platform_spec.rb
@@ -203,7 +203,6 @@ G
let(:engine_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{not_local_tag}\", :engine_version => \"#{RUBY_VERSION}\"" }
let(:engine_version_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_engine_version}\"" }
let(:patchlevel_incorrect) { "#{ruby_version_correct}, :patchlevel => '#{not_local_patchlevel}'" }
- let(:patchlevel_fixnum) { "#{ruby_version_correct}, :patchlevel => #{RUBY_PATCHLEVEL}1" }
def should_be_ruby_version_incorrect
expect(exitstatus).to eq(18) if exitstatus
@@ -225,11 +224,6 @@ G
expect(out).to be_include("Your Ruby patchlevel is #{RUBY_PATCHLEVEL}, but your Gemfile specified #{not_local_patchlevel}")
end
- def should_be_patchlevel_fixnum
- expect(exitstatus).to eq(18) if exitstatus
- expect(out).to be_include("The Ruby patchlevel in your Gemfile must be a string")
- end
-
context "bundle install" do
it "installs fine when the ruby version matches" do
install_gemfile <<-G
@@ -1225,25 +1219,5 @@ G
should_be_patchlevel_incorrect
end
end
-
- it "fails when the patchlevel is a fixnum" do
- simulate_ruby_engine "jruby" do
- update_repo2 do
- build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
- end
-
- gemfile <<-G
- source "file://#{gem_repo2}"
- gem "activesupport", "2.3.5"
- gem "foo", :git => "#{lib_path('foo')}"
-
- #{patchlevel_fixnum}
- G
-
- bundle "outdated"
- should_be_patchlevel_fixnum
- end
- end
end
end