Почему не удается сравнить замороженные версии Gem? - PullRequest
0 голосов
/ 03 июля 2019

Я пишу что-то в Ruby, которое должно сравнивать версии, чтобы определить, нужно ли что-то обновлять.

Но когда я запускаю current_version <=> desired_version и хотя бы одна из версий зависла, я получаю:

    4: from .../ruby/2.6.0/rubygems/version.rb:344:in `<=>'
    3: from .../ruby/2.6.0/rubygems/version.rb:371:in `canonical_segments'
    2: from .../ruby/2.6.0/rubygems/version.rb:393:in `_split_segments'
    1: from .../ruby/2.6.0/rubygems/version.rb:387:in `_segments'
FrozenError (can't modify frozen Gem::Version)

Согласно документам , исходный код такой:

def <=>(other)
  return unless Gem::Version === other
  return 0 if @version == other._version || canonical_segments == other.canonical_segments

  lhsegments = _segments
  rhsegments = other._segments

  lhsize = lhsegments.size
  rhsize = rhsegments.size
  limit  = (lhsize > rhsize ? lhsize : rhsize) - 1

  i = 0

  while i <= limit
    lhs, rhs = lhsegments[i] || 0, rhsegments[i] || 0
    i += 1

    next      if lhs == rhs
    return -1 if String  === lhs && Numeric === rhs
    return  1 if Numeric === lhs && String  === rhs

    return lhs <=> rhs
  end

  return 0
end

Я не понимаю, почему этот код изменял бы состояние самоцвета. Я что-то упускаю?

1 Ответ

1 голос
/ 03 июля 2019

Ошибка говорит вам, где: метод <=> вызывает canonical_segments, который вызывает _split_segments, который вызывает _segments. Так что это , где должна происходить мутация; не напрямую в методе, который вы скопировали в посте.

Точнее, вот исходный код, вызывающий проблемы :

  def canonical_segments
    @canonical_segments ||=
      _split_segments.map! do |segments|
        segments.reverse_each.drop_while {|s| s == 0 }.reverse
      end.reduce(&:concat)
  end

  protected

  def _version
    @version
  end

  def _segments
    # segments is lazy so it can pick up version values that come from
    # old marshaled versions, which don't go through marshal_load.
    # since this version object is cached in @@all, its @segments should be frozen

    @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
      /^\d+$/ =~ s ? s.to_i : s
    end.freeze
  end

  def _split_segments
    string_start = _segments.index {|s| s.is_a?(String) }
    string_segments  = segments
    numeric_segments = string_segments.slice!(0, string_start || string_segments.size)
    return numeric_segments, string_segments
  end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...