根据日期或 Ruby 版本设置 Ruby 环境

Posted

技术标签:

【中文标题】根据日期或 Ruby 版本设置 Ruby 环境【英文标题】:Setup Ruby environment based on date or Ruby version 【发布时间】:2021-08-24 15:19:51 【问题描述】:

出于测试目的,我想安装一个基于过去日期的 Ruby 环境。例如,Ruby 2.5.0p0 于 2017 年 12 月 25 日发布,在某处我读到 Rails 5.2.6 是使用它的版本。我想要的是一种编程方式来了解 gem 的版本/日期应该与什么版本的 Ruby 一起使用。我错过了一些超级简单的方法吗?

编辑:

我在某个日期就已经存在的 Ruby 环境中进行测试的想法似乎很难处理,而且可能没有必要。所以我要做的是运行几个主要的 Ruby 版本并安装它们的 best Rails versions 并让所有其他 gem 浮动到任何版本。

Ruby    Rails
2.5.0   5.2.6
2.5.9   5.2.6
2.6.7   6.0.3.7
2.7.3   6.0.3.7
3.0.1   latest

【问题讨论】:

Rails 维护了每个主要 Rails 版本支持的Ruby Versions 的官方列表。 这是基于一个错误的假设,即 gem 上只有一个版本可以与某个版本的 Ruby 配合使用。现实并非如此——相反,您可以通过使用 bundler 或 ruby​​gems.org API 获得给定 Ruby 版本的兼容 gem 版本列表。 @max,您能否提供一个示例代码行来生成“给定 Ruby 版本的兼容 gem 版本列表”? @oaklodge 如果您查看random gem on rubygems.org,您可能会看到它的内容类似于:REQUIRED RUBY VERSION: >= 2.5.0bundler 使用此信息,然后为项目安装依赖项。 换句话说,例如,您不能将 ruby​​ 2.4 与 nokigiri 1.11.7 一起使用。但是您也不需要知道/关心哪个是支持 ruby​​ 2.4 的最新版本的 nokogiri,因为 bundler 会自动为您找出答案! 【参考方案1】:

Rails 和所有其他 gem 可以声明最低要求的 ruby​​ 版本。运行 bundle update 时会自动考虑这一点。

但是,有两个问题:

    库作者并不总是完美地做到这一点 - 因此,您可能会使用古老的 ruby​​ 版本运行现代 gem,并且只在运行时发现不兼容。

    图书馆作者无法预测未来;他们可能会正确指定 最低 所需的 ruby​​ 版本,但他们不可能提前知道 最大 兼容的 ruby​​ 版本。

但是,有一线希望:Ruby 非常擅长向后兼容。因此,除非您尝试使用古老的库和现代 ruby​​ 运行一个大型项目(例如,使用 ruby​​ 2.7 的 rails 4 项目),否则您不太可能在这里遇到很多问题。

而且,正如我在上面所建议的,这可能只是 大型 gems 的问题,例如 rails 框架。 It's fairly well documented which minimum version of ruby is supported by each major rails release:

Rails 7 需要 Ruby 2.7.0 或更高版本。

Rails 6 需要 Ruby 2.5.0 或更高版本。

Rails 5 需要 Ruby 2.2.2 或更高版本。

【讨论】:

根据我的经验,大多数 Ruby 不兼容问题都与依赖于外部库(如 Nokogiri)的 gem 相关(以及 1 Infinite Loop 的 schenanigans)。【参考方案2】:

我想要的是一种编程方式来了解 gem 的版本/日期 应该使用什么版本的 Ruby。

一种方法是使用the API provided by RubyGems.org:

# run with ruby get_versions.rb gemname rubyversion

require 'json'
require 'uri'
require 'net/http'
require 'pp'

gemname = ARGV[0] || 'rails'
uri = URI("https://rubygems.org/api/v1/versions/#gemname.json")
target_ruby_version = Gem::Version.new(ARGV[1] || '2.7.0')

puts "getting #uri"

response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  puts '...'
  request = Net::HTTP::Get.new uri
  http.request(request)
end
# error handling is boring so lets just assume this will always work
json = JSON.parse(response.body)
compatible = json.each_with_object() do |gem_version, hash|
  hash[gem_version["number"]] = gem_version["ruby_version"]
end.select do |gemv, rubyv|
  Gem::Requirement.new(rubyv)
                  .satisfied_by?(target_ruby_version)
end

puts "The following versions of #gemname satifisy the Ruby requirement #target_ruby_version:"

pp compatible.keys

但是,它在测试 gem 是否与给定版本的 Ruby 真正兼容时的实际用处是非常值得怀疑的。由于作者通常不指定 ruby​​ 版本的范围,它只会告诉您给定的 Ruby 版本是否满足最低版本要求。 Tom Lord 很好地描述了为什么这是有问题的。

您在 Ruby 2.7.0 上运行 Rails 0.8.0 的体验可能会有所不同。

【讨论】:

以上是关于根据日期或 Ruby 版本设置 Ruby 环境的主要内容,如果未能解决你的问题,请参考以下文章

如何为项目设置特定的 Ruby 版本(无 rvm 和 rbenv)

使用 rvmrc 或 ruby​​-version 文件使用 RVM 设置项目 gemset?

Windows环境下Ruby离线安装gem包

pod search 报错 ruby环境问题#yyds干货盘点#

如何根据 if-then 决策树设置 ruby​​ 变量

sh 设置Ruby on Rails环境