Ruby wrapper for the RubyGems.org API.
Install the gem and add to the application's Gemfile:
bundle add gems
Or, if Bundler is not being used to manage dependencies:
gem install gems
https://www.rubydoc.info/gems/gems
require 'gems'
# Return some basic information about rails.
gem = Gems.rubygem 'rails'
gem.name # => "rails"
gem.version # => "8.1.2"
gem.downloads # => 704478420
gem.runtime_dependencies.map(&:name) # => ["actioncable", "actionmailbox", ...]
# Return some basic information about rails version 7.0.6.
version = Gems.version 'rails', '7.0.6'
version.number # => "7.0.6"
version.built_at # => 2023-06-29 00:00:00 UTC
version.sha # => "5dfbd481..."
# Return information about a version for a specific platform.
Gems.version 'nokogiri', '1.15.0', platform: 'java'
# Return the SHA-256 checksum of every file in a version.
Gems.contents('rails', '8.1.3.1')['README.md']['sha256']
# Return the sigstore attestations published with a version.
Gems.attestations 'rails', '8.1.3.1'
Gems.attestations 'nokogiri', '1.15.0', platform: 'java'
# Return an array of active gems that match the query.
Gems.search 'cucumber'
# Return the names of gems that match the query, for a search box.
Gems.autocomplete 'nokogiri'
# Return all gems that you own.
Gems.owned_gems
# Return all gems owned by Erik Berlin.
Gems.owned_gems 'sferik'
# Return basic information about a user, by handle or ID.
Gems.profile('sferik').handle
# Submit a gem to RubyGems.org.
Gems.push File.new 'gemcutter-0.2.1.gem'
# Remove a gem from RubyGems.org's index.
# Defaults to the latest version if no version is specified.
Gems.yank 'bills', '0.0.1'
# Update a previously yanked gem back into RubyGems.org's index.
# Defaults to the latest version if no version is specified.
Gems.unyank 'bills', '0.0.1'
# Return an array of versions of coulda.
Gems.versions('coulda').map(&:number)
# Return the latest version of coulda.
Gems.latest_version 'coulda'
# Return the total number of downloads of all gems.
Gems.total_downloads
# Return the number of downloads of rails_admin and of version 0.0.1.
# (Defaults to the latest version if no version is specified.)
Gems.downloads('rails_admin', '0.0.1').version_downloads
# Returns an array containing the top 50 downloaded gem versions of all time.
Gems.most_downloaded.first.full_name
# View all owners of a gem that you own.
Gems.owners('gemcutter').map(&:handle)
# Add an owner to a RubyGem you own, giving that user permission to manage it.
Gems.add_owner 'gemcutter', 'josh@technicalpickles.com'
# Add a maintainer, who can push but cannot manage owners.
Gems.add_owner 'gemcutter', 'josh@technicalpickles.com', role: 'maintainer'
# Change the role of an existing owner.
Gems.update_owner 'gemcutter', 'josh@technicalpickles.com', role: 'owner'
# Remove a user's permission to manage a RubyGem you own.
Gems.remove_owner 'gemcutter', 'josh@technicalpickles.com'
# Return all the webhooks registered under your account.
Gems.web_hooks.map(&:url)
# Add a webhook.
Gems.add_web_hook 'rails', 'http://example.com'
# Remove a webhook.
Gems.remove_web_hook 'rails', 'http://example.com'
# Test fire a webhook.
Gems.fire_web_hook 'rails', 'http://example.com'
# Returns the 50 gems most recently added to RubyGems.org
Gems.latest
# Returns the 50 most recently updated gems
Gems.just_updated
# Returns the gem versions created in a timeframe of up to seven days, 30 at a time.
Gems.timeframe_versions from: Time.now - 86_400
Gems.timeframe_versions from: '2019-01-18T21:24:29Z', to: '2019-01-19T21:24:29Z', page: 2
# Create an API key using HTTP basic authentication.
# The key is only returned once, so store it somewhere safe.
Gems.configure do |config|
config.username = 'nick@gemcutter.org'
config.password = 'schwwwwing'
end
Gems.create_api_key('ci-push', push_rubygem: true).key
# Create a key restricted to one gem that expires in a day and requires a one-time passcode.
Gems.create_api_key('ci-push', push_rubygem: true, rubygem_name: 'gems', expires_at: Time.now + 86_400, mfa: true)
# Return your own profile, including its multi-factor authentication level.
Gems.me.mfa
# Update the scopes of an API key.
Gems.update_api_key 'rubygems_701243f217cdf23b1370c7b66b65ca97', yank_rubygem: true
# Exchange an OIDC ID token for an API key via trusted publishing.
Gems.exchange_trusted_publisher_token(ENV.fetch('ID_TOKEN')).key
# The following methods require authentication.
# By default, we load your API key from ~/.gem/credentials
# You can override this default by specifying a custom API key.
Gems.configure do |config|
config.key = '701243f217cdf23b1370c7b66b65ca97'
end
# If your account requires multi-factor authentication, provide a one-time passcode.
Gems.configure do |config|
config.otp = '123456'
end
# For trusted publishing, provide an OIDC ID token instead of an API key.
# It is exchanged for an API key on the first request.
Gems.configure do |config|
config.id_token = ENV.fetch('ID_TOKEN')
end
# Alternatively, create a client with its own credentials and settings.
client = Gems::Client.new(key: '701243f217cdf23b1370c7b66b65ca97', host: 'https://gems.example.com')
client.rubygem 'rails'Responses are wrapped in objects with readers for each documented field: Gems::Gem, Gems::Version,
Gems::Dependency, Gems::Owner, Gems::Profile, Gems::WebHook, Gems::Downloads, and Gems::ApiKey.
Timestamps are parsed into Time objects and boolean fields have predicate readers such as yanked?. Objects are
accepted wherever their identifier is expected, so Gems.versions(gem), Gems.remove_owner(gem, owner), and
Gems.key = api_key all work.
Objects compare by identity (a gem or version by its name, version number, and platform, and so on), so
Gems.rubygem('rails') == Gems.rubygem('rails') even when download counts have changed in between. Every object also exposes
the raw response through [] and to_h, so fields without a reader remain accessible:
gem = Gems.rubygem 'rails'
gem['dependencies'] # => {"development" => [...], "runtime" => [...]}
gem.to_h # => the parsed JSON responseClients default to the global configuration, which can be set with Gems.configure or overridden per client:
| Option | Description | Default |
|---|---|---|
host |
The RubyGems-compatible host, including scheme | RUBYGEMS_HOST or https://rubygems.org |
key |
The API key sent in the Authorization header |
~/.gem/credentials |
username |
The username for HTTP basic authentication | nil |
password |
The password for HTTP basic authentication | nil |
otp |
The one-time passcode sent in the OTP header |
nil |
id_token |
The OIDC ID token exchanged for an API key | nil |
user_agent |
The User-Agent header |
Gems <version> |
open_timeout |
The timeout for opening connections, in seconds | 60 |
read_timeout |
The timeout for reading responses, in seconds | 60 |
write_timeout |
The timeout for writing requests, in seconds | 60 |
debug_output |
An IO that receives HTTP debug output | nil |
proxy_url |
The proxy to use | http_proxy/https_proxy environment |
max_redirects |
The maximum number of redirects to follow | 10 |
Each authentication method has its own authenticator class: Gems::ApiKeyAuthenticator, Gems::BasicAuthenticator,
Gems::TrustedPublisherAuthenticator, and Gems::OtpAuthenticator (which wraps one of the others).
HTTP basic authentication takes precedence over trusted publishing, which takes precedence over the API key.
Proxies are read from the http_proxy, https_proxy, and no_proxy environment variables unless proxy_url is set.
All errors inherit from Gems::Error. HTTP errors are Gems::HTTPError subclasses that expose the response and
status code, with specific classes such as Gems::NotFound, Gems::Unauthorized, and Gems::Forbidden.
Network failures raise Gems::NetworkError and redirect loops raise Gems::TooManyRedirects.
After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rake to run the tests,
linters, mutation tests, type checker, and documentation checks. Coverage, mutation testing, and type checking need
Ruby 3.3 or later; on older Rubies those tasks are skipped. You can also run bin/console for an interactive prompt
that will allow you to experiment.
This library aims to support and is tested against the following Ruby implementations:
- Ruby 3.1
- Ruby 3.2
- Ruby 3.3
- Ruby 3.4
- JRuby
If something doesn't work on one of these interpreters, it's a bug.
This library may inadvertently work (or seem to work) on other Ruby implementations, however support will only be provided for the versions listed above.
If you would like this library to support another Ruby version, you may volunteer to be a maintainer. Being a maintainer entails making sure all tests run and pass on that implementation. When something breaks on your implementation, you will be responsible for providing patches in a timely fashion. If critical issues for a particular implementation exist at the time of a major release, support for that Ruby version may be dropped.
Copyright (c) 2011-2026 Erik Berlin. See LICENSE for details.