Странные результаты для метода Gem.latest_version_for (name) - PullRequest
0 голосов
/ 07 декабря 2018

Я работаю над утилитой, связанной с драгоценными камнями, и наблюдаю странные результаты при использовании метода Gem.latest_version_for.Вот некоторые наблюдения в разделе 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:\Sites\mysh
8 mysh>ruby --version
ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
C:\Sites\mysh
9 mysh>gem --version
2.5.2

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

С превосходной помощью Джея Дорси, я думаю, я добился здесь некоторого прогресса.То, что мне нужно сказать, слишком велико, чтобы вписаться в комментарий, и это фактический ответ на вопрос о странном поведении.Ну, по крайней мере, я почти уверен, что это так.

Как уже упоминалось выше: latest_version_for вызывает latest_spec_for, который вызывает Gem :: SpecFetcher.spec_for_dependency.

Ключ в том, что этот метод затем вызывает Gem :: SpecFetcher.search_for_dependency.Это длинный бессвязный метод.Я хочу сфокусировать одну строку, которая появляется после получения спецификаций:

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

Это сортирует кортежи, которые являются массивом массивов [spec, source].Он сортирует их по возрастанию версии / платформы (насколько я могу судить)

Теперь мы вернемся к методу класса Gem latest_spec_for (name) и, в частности, к строке:

spec, = spec_tuples.first

Thisзахватывает первый вложенный массив, сохраняет спецификацию и удаляет источник.

Обратите внимание, что он захватывает первый элемент.Тот, с самым низким номером версии.Обычно это не проблема, потому что для подавляющего большинства драгоценных камней присутствует только одна спецификация.Не так для драгоценности Госу.Здесь их три из-за того, что gosu содержит специфичный для платформы код.Кажется, что нужны спецификации для двух платформ Gem («ruby» и «x86-mingw32»), а также для платформы ruby ​​(i386-mingw32).

Чтобы проверить мою идею, я создал файл glmp.rb(получите последнее исправление обезьяны) Вот оно:

# 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:\Sites\ideas\gem_usage
37 mysh>ls
gem_latest.rb  gem_usage.rb  glmp.rb
C:\Sites\ideas\gem_usage
39 mysh>=require './glmp'
true
C:\Sites\ideas\gem_usage
40 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.14.4")

Хотя сейчас я могу использовать этот хак для решения своей проблемы, я думаю, что я подниму проблему с рубинами, поднимающими этот вопрос.

0 голосов
/ 07 декабря 2018

Последняя версия, доступная для платформы i386-mingw32, - 0.7.38.Вы заметите, что это соответствует тому, что сообщается в вашей версии ruby.

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

latest_version_for вызывает latest_spec_for, что вызывает Gem::SpecFetcher.spec_for_dependency только с именем драгоценного камняв качестве аргумента.spec_for_dependency принимает другой аргумент, matching_platform, который по умолчанию равен true.

Похоже, что latest_version_for ограничен вашей текущей платформой через эту цепочку со значением matching_platform по умолчанию.Команда gem install может рассматривать i386 / x386 как то же самое / эквивалентное и разрешать их.

spec_for_dependency

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...