Gem.latest_version_fr(name)方法的奇怪结果



我正在开发一个与gem相关的实用程序,使用gem.latest_version_r方法观察到了奇怪的结果。以下是在irb:下的一些观察结果

irb(main):001:0> Gem.latest_version_for('rails').to_s
=> "5.2.2"
irb(main):002:0> Gem.latest_version_for('gosu').to_s
=> "0.7.38"

请注意,在我写这篇文章的时候,第一行是如何获得正确版本的rails的,5.2.2,并通过rubygems.org进行检查证实了这一点。对gosu gem的查询返回0.7.38,这是大错特错的。正确答案应为0.14.4

我无法解释这里发生的事情。

我可以确认我的主人是https://rubygems.org和

C:Sitesmysh
8 mysh>ruby --version
ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
C:Sitesmysh
9 mysh>gem --version
2.5.2

i386-mingw32平台的最新版本为0.7.38。你会注意到这与你的ruby版本报告的一致。

https://rubygems.org/gems/gosu/versions

latest_version_for调用latest_spec_for,后者仅以gem的名称作为参数来调用Gem::SpecFetcher.spec_for_dependencyspec_for_dependency采用另一个参数matching_platform,默认值为true。

看起来latest_version_for通过该链的作用域是您当前的平台,默认为matching_platformgem install命令可能会将i386/x386视为相同的/等效的,并允许它们。

独立规范

if matching_platform is false, gems for all platforms are returned

您应该能够镜像latest_spec_for方法,并传入要重写的multi_platform参数。类似的东西

dependency     = Gem::Dependency.new name
fetcher        = Gem::SpecFetcher.fetcher
spec_tuples, _ = fetcher.spec_for_dependency dependency, true # true added here

在Jay Dorsey的出色帮助下,我想我在这里取得了一些进步。我需要说的太大了,无法放在评论中,这是关于奇怪行为问题的实际答案。至少我很确定是的。

如上所述:latest_version_fr调用latestrongpec_for,后者调用Gem::SpecFetcher.spec_for_dependency.

关键是该方法调用Gem::SpecFetcher.search_for_dependency。这是一个长时间的散序方法。我想关注在获得规格后发生的一行:

tuples = tuples.sort_by { |x| x[0] }

这将对元组进行排序,元组是[spec,source]数组的数组。它按升序/平台对它们进行排序(据我所知(

现在我们回到Gem类方法latestrongpec_for(name(,特别是行:

spec, = spec_tuples.first

这将获取第一个子数组并保留规范并丢弃源。

请注意,它抓住了第一个元素。版本号最低的一个。这通常不是问题,因为对于绝大多数宝石来说,只有一个规格。gosu宝石则不然。这里有三个,因为gosu包含特定于平台的代码。它似乎掌握了两个Gem平台("ruby"one_answers"x86-ming32"(以及ruby平台(i386-mingw32(的规格。

为了测试我的想法,我创建了文件glmp.rb(获取最后一个monkey补丁(

# The latest_spec_for(name) monkey patch.
module Gem
# Originally in  File rubygems.rb at line 816
def self.latest_spec_for(name)
dependency   = Gem::Dependency.new name
fetcher      = Gem::SpecFetcher.fetcher
spec_tuples, = fetcher.spec_for_dependency dependency
spec_tuples[-1][0]
end
end

现在我知道猴子补丁是不受欢迎的,但现在这只是为了测试这个想法。以下是我的结果:

36 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.7.38")
C:Sitesideasgem_usage
37 mysh>ls
gem_latest.rb  gem_usage.rb  glmp.rb
C:Sitesideasgem_usage
39 mysh>=require './glmp'
true
C:Sitesideasgem_usage
40 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.14.4")

虽然我现在可以使用这个破解来解决我的问题,但我想我会向rubygems提出这个问题。

最新更新