Repository: ruby/rubygems (Ruby)

Issue:
Gem::Platform.match no longer behaves properly with a String argument
### Describe the problem as clearly as you can

When passing a string to `Gem::Platform.match`, the behavior of the method is the same as before 1b9f7f5 introduced a fix for musl platforms.

Although `Gem::Platform#=~` properly coerces the `other` argument, the `#match` method, when passed a `String`, will instead invoke `String#=~`.

The interesting bit can be seen in the docstring for `String#=~` (from https://ruby-doc.org/core-3.1.2/String.html#method-i-3D~)

> If the given object is not a Regexp, returns the value returned by object =~ self.

thereby avoiding the intended behavior change of 1b9f7f5


### Did you try upgrading RubyGems?

Present in 3.3.22

### Post steps to reproduce the problem

On a `x86_64-linux-musl` system (e.g., `ruby:3.1-alpine` image):

```ruby
#! /usr/bin/env ruby

Gem::VERSION # => "3.3.22"
Gem::Platform.local # => #<Gem::Platform:0x00007fda5ca0e0b8 @cpu="x86_64", @os="linux", @version="musl">

gem_platform_string = "x86_64-linux"
gem_platform = Gem::Platform.new(gem_platform_string)

Gem::Platform.match(gem_platform_string) # => false
Gem::Platform.match(gem_platform) # => true
```

### Run `gem env` and paste the output below

```
RubyGems Environment:
  - RUBYGEMS VERSION: 3.3.22
  - RUBY VERSION: 3.1.2 (2022-04-12 patchlevel 20) [x86_64-linux-musl]
  - INSTALLATION DIRECTORY: /usr/local/bundle
  - USER INSTALLATION DIRECTORY: /root/.local/share/gem/ruby/3.1.0
  - RUBY EXECUTABLE: /usr/local/bin/ruby
  - GIT EXECUTABLE: 
  - EXECUTABLE DIRECTORY: /usr/local/bundle/bin
  - SPEC CACHE DIRECTORY: /root/.local/share/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /usr/local/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - x86_64-linux-musl
  - GEM PATHS:
     - /usr/local/bundle
     - /root/.local/share/gem/ruby/3.1.0
     - /usr/local/lib/ruby/gems/3.1.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => true
     - :bulk_threshold => 1000
     - "install" => "--no-document"
     - "update" => "--no-document"
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /usr/local/bundle/bin
     - /usr/local/sbin
     - /usr/local/bin
     - /usr/sbin
     - /usr/bin
     - /sbin
     - /bin
```

### Proposed fix

I think the right thing to do here is to coerce the argument to a `Gem::Platform` object, so something like:

```patch
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 06de5de..1dacc59 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -22,6 +22,7 @@ def self.match(platform)
   end
 
   def self.match_platforms?(platform, platforms)
+    platform = Gem::Platform.new(platform) unless platform.is_a?(Gem::Platform)
     platforms.any? do |local_platform|
       platform.nil? ||
         local_platform == platform ||
```

I couldn't figure out how to write a nice test for this, but hopefully I've provided enough detail?



Discussion:
I've submitted a PR with a test and a fix at https://github.com/rubygems/rubygems/pull/5939



Patch:
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 06de5ded8da6..1dacc596c47b 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -22,6 +22,7 @@ def self.match(platform)
   end
 
   def self.match_platforms?(platform, platforms)
+    platform = Gem::Platform.new(platform) unless platform.is_a?(Gem::Platform)
     platforms.any? do |local_platform|
       platform.nil? ||
         local_platform == platform ||


Test patch:
diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb
index f683204a2fc2..3bd4a862c524 100644
--- a/test/rubygems/test_gem_platform.rb
+++ b/test/rubygems/test_gem_platform.rb
@@ -452,6 +452,13 @@ def test_inspect
     assert_equal 1, result.scan(/@version=/).size
   end
 
+  def test_gem_platform_match_with_string_argument
+    util_set_arch "x86_64-linux-musl"
+
+    assert(Gem::Platform.match(Gem::Platform.new("x86_64-linux")), "should match Gem::Platform")
+    assert(Gem::Platform.match("x86_64-linux"), "should match String platform")
+  end
+
   def assert_local_match(name)
     assert_match Gem::Platform.local, name
   end