我正在开发一个与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_dependency
。spec_for_dependency
采用另一个参数matching_platform
,默认值为true。
看起来latest_version_for
通过该链的作用域是您当前的平台,默认为matching_platform
。gem 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提出这个问题。