From start to finish, learn how to package your Ruby code in a gem.
* [Introduction](#introduction) * [Your first gem](#your-first-gem) * [Starting with bundle gem](#starting-with-bundle-gem) * [Requiring more files](#requiring-more-files) * [Using other gems](#using-other-gems) * [Writing tests](#writing-tests) * [Adding an executable](#adding-an-executable) * [Documenting your code](#documenting-your-code) * [Releasing your gem](#releasing-your-gem) * [Wrapup](#wrapup) Introduction ------------ Why create a gem? You could just throw some code into your other project and use it directly. But what if you want to use that code elsewhere, or share it with others? A gem lets you package your library separately and reuse it across projects with a simple `gem install` or a line in a Gemfile. When you need it in another project, it’s a tiny modification rather than a whole lot of copying. Creating and publishing your own gem is simple thanks to the tools baked right into RubyGems. Let’s make a simple “hello world” gem, and feel free to play along at home! The code for the gem we’re going to make here is up [on GitHub](https://github.com/qrush/hola). Your first gem -------------- I started with just one Ruby file for my `hola` gem, and the gemspec. You'll need a new name for yours (maybe `hola_yourusername`) to publish it. Check the Patterns guide for [basic recommendations](/patterns/#consistent-naming) to follow when naming a gem. $ tree . ├── hola.gemspec └── lib └── hola.rb Code for your package is placed within the `lib` directory. The convention is to have *one* Ruby file with the *same* name as your gem, since that gets loaded when `require "hola"` is run. That one file is in charge of setting up your gem's code and API. The code inside of `lib/hola.rb` is pretty bare bones. It just makes sure that you can see some output from the gem: $ cat lib/hola.rb class Hola def self.hi puts "Hello world!" end end The gemspec defines what’s in the gem, who made it, and the version of the gem. It’s also your interface to [RubyGems.org](https://rubygems.org). All of the information you see on a gem page (like [jekyll](https://rubygems.org/gems/jekyll)’s) comes from the gemspec. $ cat hola.gemspec Gem::Specification.new do |s| s.name = "hola" s.version = "0.0.0" s.summary = "Hola!" s.description = "A simple hello world gem" s.authors = ["Nick Quaranto"] s.email = "nick@quaran.to" s.files = ["lib/hola.rb"] s.homepage = "https://rubygems.org/gems/hola" s.license = "MIT" end > The description member can be much longer than you see in this example. If it > matches `/^== [A-Z]/` then the description will be run through > [RDoc's markup formatter](https://github.com/ruby/rdoc) for display on > the RubyGems web site. Be aware though that other consumers of the data might > not understand this markup. Look familiar? The gemspec is also Ruby, so you can wrap scripts to generate the file names and bump the version number. There are lots of fields the gemspec can contain. To see them all check out the full [reference](/specification-reference/). After you have created a gemspec, you can build a gem from it. Then you can install the generated gem locally to test it out. $ gem build hola.gemspec Successfully built RubyGem Name: hola Version: 0.0.0 File: hola-0.0.0.gem $ gem install ./hola-0.0.0.gem Successfully installed hola-0.0.0 Parsing documentation for hola-0.0.0 Installing ri documentation for hola-0.0.0 Done installing documentation for hola after 0 seconds 1 gem installed Of course, the smoke test isn’t over yet: the final step is to `require` the gem and use it: $ irb 3.1.2 :001 > require "hola" => true 3.1.2 :002 > Hola.hi Hello world! => nil Now you can share hola with the rest of the Ruby community. See the [Releasing your gem](#releasing-your-gem) section below to learn how to publish it to RubyGems.org. Starting with bundle gem ------------------------ While you can set up a gem manually as shown above, Bundler provides a convenient `bundle gem` command that generates a scaffold with everything you need. This is the recommended way to start a new gem: $ bundle gem foodie This creates a directory with the following structure: * **Gemfile**: Manages gem dependencies for development. Contains a `gemspec` line meaning that Bundler will include dependencies specified in _foodie.gemspec_ too. Runtime dependencies belong in the _gemspec_, while development dependencies are declared here. See [Gemfile and gemspec](/gemfile-and-gemspec) for how the two files divide the work. * **Rakefile**: Includes Bundler’s `build`, `install` and `release` Rake tasks by way of calling `Bundler::GemHelper.install_tasks`. * **foodie.gemspec**: The gem specification file, just like the one we wrote manually. Fields to complete include `description`, `homepage`, `metadata["source_code_uri"]`, and `metadata["changelog_uri"]`. * **lib/foodie.rb**: The main file loaded when the gem is required. * **lib/foodie/version.rb**: Defines a `VERSION` constant used by the gemspec. * **.gitignore**: Ignores the _pkg_ directory, _.gem_ files, and _.bundle_ directory. The command will also ask whether you want to include a `CODE_OF_CONDUCT.md` and `LICENSE.txt`. For information on gem naming conventions, see the [Name Your Gem](/name-your-gem/) guide. After running `bundle gem`, you can build and install the gem using Rake tasks: $ rake build # Build the gem into the pkg directory $ rake install # Build and install the gem to your system Requiring more files -------------------- Having everything in one file doesn't scale well. Let's add some more code to this gem. $ cat lib/hola.rb class Hola def self.hi(language = "english") translator = Translator.new(language) translator.hi end end class Hola::Translator def initialize(language) @language = language end def hi case @language when "spanish" "hola mundo" else "hello world" end end end This file is getting pretty crowded. Let's break out the `Translator` into a separate file. As mentioned before, the gem's root file is in charge of loading code for the gem. The other files for a gem are usually placed in a directory of the same name of the gem inside of `lib`. We can split this gem out like so: $ tree . ├── hola.gemspec └── lib ├── hola │ └── translator.rb └── hola.rb The `Translator` is now in `lib/hola`, which can easily be picked up with a `require` statement from `lib/hola.rb`. The code for the `Translator` did not change much: $ cat lib/hola/translator.rb class Hola::Translator def initialize(language) @language = language end def hi case @language when "spanish" "hola mundo" else "hello world" end end end But now the `hola.rb` file has some code to load the `Translator`: $ cat lib/hola.rb class Hola def self.hi(language = "english") translator = Translator.new(language) translator.hi end end require 'hola/translator' > Gotcha: > For newly created folder/file, do not forget to add one entry in hola.gemspec > file, as shown- $ cat hola.gemspec Gem::Specification.new do |s| ... s.files = ["lib/hola.rb", "lib/hola/translator.rb"] ... end > without the above change, the new folder would not be included into the > installed gem. Let's try this out. First, fire up `irb`: $ irb -Ilib -rhola 3.1.2 :001 > Hola.hi("english") => "hello world" 3.1.2 :002 > Hola.hi("spanish") => "hola mundo" We need to use a strange command line flag here: `-Ilib`. Usually RubyGems includes the `lib` directory for you, so end users don't need to worry about configuring their load paths. However, if you're running the code outside of RubyGems, you have to configure things yourself. It's possible to manipulate the `$LOAD_PATH` from within the code itself, but that's considered an anti-pattern in most cases. There are many more anti-patterns (and good patterns!) for gems, explained in [this guide](/patterns/). If you've added more files to your gem, make sure to remember to add them to your gemspec's `files` array before publishing a new gem! For this reason (among others), many developers automate this with [Hoe](https://github.com/seattlerb/hoe), [Jeweler](https://github.com/technicalpickles/jeweler), [Rake](https://github.com/ruby/rake), [lorem](https://github.com/railscasts/245-new-gem-with-bundler/tree/HEAD/lorem), or [just a dynamic gemspec ](https://github.com/wycats/newgem-template/blob/master/newgem.gemspec). Adding more directories with more code from here is pretty much the same process. Split your Ruby files up when it makes sense! Making a sane order for your project will help you and your future maintainers from headaches down the line. Using other gems ----------------- If your gem depends on another gem, you can specify it in your gemspec using `add_dependency`. For example, to depend on `activesupport`: Gem::Specification.new do |s| ... s.add_dependency "activesupport", ">= 7.0" end Using `>=` (an optimistic version constraint) is recommended in most cases, so that your gem does not artificially lock its users out of future releases of the dependency. See [Optimistic vs. pessimistic constraints](/versioning#optimistic-vs-pessimistic-constraints) for when a pessimistic (`~>`) constraint may be more appropriate. You can also specify development-only dependencies that are needed for testing but not at runtime: s.add_development_dependency "minitest", ">= 5.0" When using Bundler, running `bundle install` will resolve and install all dependencies specified in the gemspec. Anyone who runs `gem install yourgemname --dev` will get the development dependencies installed too. If your gem has a Gemfile alongside the gemspec, prefer declaring development dependencies in the Gemfile instead. See [Gemfile and gemspec](/gemfile-and-gemspec) for the reasoning. Writing tests -------------- Testing your gem is extremely important. Not only does it help assure you that your code works, but it helps others know that your gem does its job. When evaluating a gem, Ruby developers tend to view a solid test suite (or lack thereof) as one of the main reasons for trusting that piece of code. Gems support adding test files into the package itself so tests can be run when a gem is downloaded. In short: *TEST YOUR GEM!* Please! There are two popular test frameworks in the Ruby community: [Minitest](https://github.com/minitest/minitest) and [RSpec](https://rspec.info/). Minitest is Ruby's built-in test framework and requires no additional setup. RSpec is a widely used alternative that provides an expressive DSL for writing specs. Either works great — pick whichever you prefer and see the corresponding section below. ### Testing with Minitest Let's add some tests to Hola. This requires adding a few more files, namely a `Rakefile` and a brand new `test` directory: $ tree . ├── Rakefile ├── bin │ └── hola ├── hola.gemspec ├── lib │ ├── hola │ │ └── translator.rb │ └── hola.rb └── test └── test_hola.rb The `Rakefile` gives you some simple automation for running tests: $ cat Rakefile require "rake/testtask" Rake::TestTask.new do |t| t.libs << "test" end desc "Run tests" task default: :test Now you can run `rake test` or simply just `rake` to run tests. Woot! Here's a basic test file for hola: $ cat test/test_hola.rb require "minitest/autorun" require "hola" class HolaTest < Minitest::Test def test_english_hello assert_equal "hello world", Hola.hi("english") end def test_any_hello assert_equal "hello world", Hola.hi("ruby") end def test_spanish_hello assert_equal "hola mundo", Hola.hi("spanish") end end Finally, to run the tests: $ rake test Run options: --seed 9351 # Running: ... Finished in 0.005645s, 531.4108 runs/s, 531.4108 assertions/s. 3 runs, 3 assertions, 0 failures, 0 errors, 0 skips It's green! Well, depending on your shell colors. ### Testing with RSpec [RSpec](https://rspec.info/) is another popular testing framework. To use it, first add it as a development dependency in your gemspec: s.add_development_dependency "rspec", "~> 3.0" Then create a `spec` directory and a spec file: $ tree . ├── hola.gemspec ├── lib │ ├── hola │ │ └── translator.rb │ └── hola.rb └── spec └── hola_spec.rb Write your specs in `spec/hola_spec.rb`: $ cat spec/hola_spec.rb require "hola" describe Hola do it "says hello world in english" do expect(Hola.hi("english")).to eql("hello world") end it "says hello world by default" do expect(Hola.hi("ruby")).to eql("hello world") end it "says hola mundo in spanish" do expect(Hola.hi("spanish")).to eql("hola mundo") end end Run the specs with: $ bundle exec rspec spec 3 examples, 0 failures For more great examples, the best thing you can do is to hunt around [GitHub](https://github.com/search?q=stars%3A%3E1000+forks%3A%3E100&type=Repositories&l=Ruby) and read some code. Adding an executable -------------------- In addition to providing libraries of Ruby code, gems can also expose one or many executable files to your shell's `PATH`. Probably the best known example of this is `rake`. Another very useful one is the [Nokogiri](https://rubygems.org/gems/nokogiri) gem, which parses HTML/XML documents. Here's an example: $ gem install -N nokogiri [...] $ nokogiri https://www.ruby-lang.org/ Your document is stored in @doc... 3.1.2 :001 > @doc.title => "Ruby Programming Language" Adding an executable to a gem is a simple process. You just need to place the file in your gem's `bin` directory, and then add it to the list of executables in the gemspec. Let's add one for the Hola gem. First create the file and make it executable: $ mkdir bin $ touch bin/hola $ chmod a+x bin/hola The executable file itself just needs a [shebang](http://www.catb.org/jargon/html/S/shebang.html) in order to figure out what program to run it with. Here's what Hola's executable looks like: $ cat bin/hola #!/usr/bin/env ruby require 'hola' puts Hola.hi(ARGV[0]) All it's doing is loading up the gem, and passing the first command line argument as the language to say hello with. Here's an example of running it: $ ruby -Ilib ./bin/hola hello world $ ruby -Ilib ./bin/hola spanish hola mundo Finally, to get Hola's executable included when you push the gem, you'll need to add it in the gemspec. $ head -4 hola.gemspec Gem::Specification.new do |s| s.name = "hola" s.version = "0.0.1" s.executables << "hola" Push up that new gem, and you'll have your own command line utility published! You can add more executables as well in the `bin` directory if you need to, there's an `executables` array field on the gemspec. > Note that you should change the gem's version when pushing up a new release. > For more information on gem versioning, see [Versioning and compatibility](/versioning) Documenting your code --------------------- By default most gems use RDoc to generate docs. There are plenty of [great tutorials](https://ruby.github.io/rdoc/RDoc/Markup.html) for learning how to mark up your code with RDoc. Here's a simple example: # The main Hola driver class Hola # Say hi to the world! # # Example: # >> Hola.hi("spanish") # => hola mundo # # Arguments: # language: (String) def self.hi(language = "english") translator = Translator.new(language) puts translator.hi end end Another great option for documentation is [YARD](https://yardoc.org/), since when you push a gem, [RubyDoc.info](https://rubydoc.info/) generates YARDocs automatically from your gem. YARD is backwards compatible with RDoc, and it has a [good introduction](https://rubydoc.info/gems/yard/file/docs/GettingStarted.md) on what's different and how to use it. Releasing your gem ------------------ Publishing your gem to RubyGems.org requires an account on the site. To set up your computer with your RubyGems account, run the following command (replacing with your own Email, Password, and OTP if enabled): $ gem signin Enter your RubyGems.org credentials. Don't have an account yet? Create one at https://rubygems.org/sign_up Email: (your-email-address@example.com) Password: (your password for RubyGems.org) API Key name [host-user-20220102030405]: Please select scopes you want to enable for the API key (y/n) index_rubygems [y/N]: n push_rubygem [y/N]: y yank_rubygem [y/N]: n add_owner [y/N]: n remove_owner [y/N]: n access_webhooks [y/N]: n show_dashboard [y/N]: n You have enabled multi-factor authentication. Please enter OTP code. Code: 123456 Signed in with API key: host-user-20220102030405. > If you're having problems with curl, OpenSSL, or certificates, you might want to > simply try entering the above URL in your browser's address bar. Your browser will > ask you to login to RubyGems.org. Enter your username and password. Your browser > will now try to download the file api_key.yaml. Save it in ~/.gem and call it 'credentials' ### With gem push Once signed in, you can push the gem directly: $ gem push hola-0.0.0.gem Pushing gem to RubyGems.org... Successfully registered gem: hola (0.0.0) In just a short time (usually less than a minute), your gem will be available for installation by anyone. You can see it [on the RubyGems.org site](https://rubygems.org/gems/hola) or grab it from any computer with RubyGems installed: $ gem list -r hola *** REMOTE GEMS *** hola (0.1.3) $ gem install hola Fetching hola-0.1.3.gem Successfully installed hola-0.1.3 Parsing documentation for hola-0.1.3 Installing ri documentation for hola-0.1.3 Done installing documentation for hola after 0 seconds 1 gem installed ### With rake release If you created your gem with `bundle gem`, you can use the `rake release` command instead. This command: 1. Builds the gem into the _pkg_ directory 2. Creates a git tag for the current version 3. Pushes the tag to the git remote 4. Pushes the gem to RubyGems.org Before releasing, make sure to update the version number in your version file (e.g. `lib/hola/version.rb`) and commit all changes. To make version bumping easier, you can use the [gem-release](https://github.com/svenfuchs/gem-release) gem: $ gem install gem-release $ gem bump --version minor # bumps to the next minor version $ gem bump --version major # bumps to the next major version $ gem bump --version 1.1.1 # bumps to the specified version Wrapup ------ With this basic understanding of building your own RubyGem, we hope you'll be on your way to making your own! The next few guides cover patterns in making a gem and the other capabilities of the RubyGems system. Credits ------- This tutorial was adapted from "Gem Sawyer, Modern Day Ruby Warrior" <`http://rubylearning.com/blog/2010/10/06/gem-sawyer-modern-day-ruby-warrior/`>. The code for this gem can be found [on GitHub](https://github.com/qrush/hola). --- # Publishing your gem Source: https://guides.rubygems.org/publishing/ Start with an idea, end with a distributable package of Ruby code. Ways to share your gem code with other users. * [Introduction](#introduction) * [Sharing Source Code](#sharing-source-code) * [Serving Your Own Gems](#serving-your-own-gems) * [Publishing to RubyGems.org](#publishing-to-rubygemsorg) * [Push Permissions on RubyGems.org](#push-permissions-on-rubygemsorg) * [Gem Security](#gem-security) Introduction ------------ Now that you've [created your gem](/make-your-own-gem), you're probably ready to share it. While it is perfectly reasonable to create private gems solely to organize the code in large private projects, it's more common to build gems so that they can be used by multiple projects. This guide discusses the various ways that you can share your gem with the world. Sharing Source Code ------------------- The simplest way (from the author's perspective) to share a gem for other developers' use is to distribute it in source code form. If you place the full source code for your gem on a public git repository (often, though not always, this means sharing it via [GitHub](https://github.com)), then other users can install it with [Bundler's git functionality](/gemfile/#GIT). For example, you can install the latest code for the wicked_pdf gem in a project by including this line in your Gemfile: gem "wicked_pdf", :git => "https://github.com/mileszs/wicked_pdf.git" > Installing a gem directly from a git repository is a feature of Bundler, not > a feature of RubyGems. Gems installed this way will not show up when you run > `gem list`. Serving Your Own Gems --------------------- If you want to control who can install a gem, or directly track the activity surrounding a gem, then you'll want to set up a private gem server. You can [set up your own gem server](/run-your-own-gem-server) or use a commercial service such as [Gemfury](http://www.gemfury.com/). RubyGems 2.2.0 and newer support the `allowed_push_host` metadata value to restrict gem pushes to a single host. If you are publishing private gems you should set this value to prevent accidental pushes to rubygems.org: Gem::Specification.new 'my_gem', '1.0' do |s| # ... s.metadata['allowed_push_host'] = 'https://gems.my-company.example' end Publishing to RubyGems.org -------------------------- The simplest way to distribute a gem for public consumption is to use [RubyGems.org](https://rubygems.org/). Gems that are published to RubyGems.org can be installed via the `gem install` command or through the use of tools such as Isolate or Bundler. To begin, you'll need to create an account on RubyGems.org. Visit the [sign up](https://rubygems.org/users/new) page and supply an email address that you control, a handle (username) and a password. After creating the account, use your email and password when pushing the gem. (RubyGems saves the credentials in ~/.gem/credentials for you so you only need to log in once.) Note that your gem name must be unique. It cannot have a name that is already in use by another gem already published to [RubyGems.org](https://rubygems.org/). To publish version 0.1.0 of a new gem named 'squid-utils': $ gem push squid-utils-0.1.0.gem Enter your RubyGems.org credentials. Don't have an account yet? Create one at https://rubygems.org/sign_up Email: gem_author@example Password: Signed in. Pushing gem to RubyGems.org... Successfully registered gem: squid-utils (0.1.0) Congratulations! Your new gem is now ready for any ruby user in the world to install! Push Permissions on RubyGems.org -------------------------------- If you have multiple maintainers for your gem you can give your fellow maintainers permission to push the gem to rubygems.org through the [gem owner command](/command-reference/#gem-owner). "Access Denied" Error When Pushing to RubyGems.org -------------------------------------------------- In certain situations, you may get this error: Pushing gem to https://rubygems.org... Access Denied. Please sign up for an account at https://rubygems.org If you encounter this error and aren't sure why, try running `gem signout` and then `gem signin`. There is [an open issue about improving how this is handled](https://github.com/rubygems/rubygems/issues/7595). Gem Security ------------ See [Security](/security) page. --- # How to manage application dependencies with Bundler Source: https://guides.rubygems.org/using_bundler_in_applications/ This guide was originally written for Bundler v1.12. If you are using a different version, keep in mind that the output can differ. To check your Bundler version, simply run `bundle -v`. ## What's Inside? 1. [Getting Started - Installing Bundler and **bundle init**](#getting-started---installing-bundler-and-bundle-init) 1. [Editing Gemfile](#editing-gemfile) 1. [Sources](#sources) 1. [Adding Gems](#adding-gems) 1. [Gemfile Syntax](#gemfile-syntax) 1. [Installing Gems - **bundle install**](#installing-gems---bundle-install) 1. [Development](#development) 1. [Deployment](#deployment) 1. [Gemfile.lock](#gemfilelock) 1. [Executing Commands - **bundle exec**](#executing-commands---bundle-exec) 1. [Updating Gems - **bundle outdated** and **bundle update**](#updating-gems---bundle-outdated-and-bundle-update) 1. [Troubleshooting](#troubleshooting) 1. [Running `git bisect` in projects using Bundler](#running-git-bisect-in-projects-using-bundler) ## Getting Started - Installing Bundler and **bundle init** **Some of the frameworks have builtin support for Bundler, e.g. when you run `rails new app` it will automatically init Bundler.** Firstly, we need to install Bundler. $ gem install bundler This command will also update already installed bundler. You should get something similar as output: ~~~ bash $ gem install bundler Successfully installed bundler-1.12.5 1 gem installed ~~~ To init Bundler manually, let's do this (`bundler_example` will be folder with our app): $ mkdir bundler_example && cd bundler_example $ bundle init This will create `Gemfile` inside `bundler_example` folder: ~~~ ruby # frozen_string_literal: true # A sample Gemfile source "https://rubygems.org" # gem "rails" ~~~ ## Editing Gemfile ### Sources Auto-generated Gemfile consists of `source "https://rubygems.org"`. It means that Bundler will search for gems in `https://rubygems.org`. If you want to use your own RubyGems server or different one, just change it: ~~~ ruby source "https://your_ruby_gem_server.url" ~~~ *** If you have more gem sources, you can use block or `:source`: ~~~ ruby source "https://your_ruby_gem_server.url" do # gems end gem "my_gem", source: "https://your_2_ruby_gem_server.url" ~~~ Gems inside block will be retrieved from given source. *** Learn more about `source` [here](/gemfile/#GLOBAL-SOURCE). ### Adding Gems Let's now add some dependencies to project: ~~~ ruby # frozen_string_literal: true # A sample Gemfile source "https://rubygems.org" gem "rails" ~~~ Using above Gemfile, `bundler install` will install latest version of `rails` gem. *** What to do when we want to install specified version? Just specify it after comma: ~~~ ruby gem "rails", "3.0.0" ~~~ or use this syntax: ~~~ ruby gem "rails", "~> 4.0.0" # which is same as gem "rails", ">= 4.0.0", "< 4.1.0" gem "nokogiri", ">= 1.4.2" ~~~ *** Learn more about gems in Gemfile [here](/gemfile/#GEMS). ### Gemfile Syntax Learn more about Gemfile syntax from the [gemfile manpage](/gemfile/#SYNTAX). ## Installing Gems - **bundle install** ### Development To install gems for development, simply run `bundle install`. This should give you similar output: Fetching gem metadata from https://rubygems.org/ Fetching version metadata from https://rubygems.org/ Fetching dependency metadata from https://rubygems.org/ Resolving dependencies... Using mini_portile2 2.1.0 Using pkg-config 1.1.7 Using bundler 1.12.5 Using nokogiri 1.6.8 Bundle complete! 1 Gemfile dependency, 4 gems now installed. Use `bundle show [gemname]` to see where a bundled gem is installed. It should also create [`Gemfile.lock` file](/command-reference/bundle-install/#THE-GEMFILE-LOCK): GEM remote: https://rubygems.org/ specs: mini_portile2 (2.1.0) nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) pkg-config (1.1.7) PLATFORMS ruby DEPENDENCIES nokogiri (>= 1.4.0) BUNDLED WITH 1.12.5 This Gemfile.lock is described in [next chapter](#gemfilelock). ### Deployment For deployment you should use [`--deployment` option](/command-reference/bundle-install/#DEPLOYMENT-MODE): $ bundle install --deployment This will install all dependencies to `./vendor/bundle`. To run this command, there are some requirements: 1. `Gemfile.lock` file is required. 1. `Gemfile.lock` must be up to date. *** To learn more about `bundle install` command click [here](/command-reference/bundle-install/). ## Gemfile.lock Bundler uses this file to save names and versions of all gems. It guarantees that you always use the same exact code, even as your application moves across machines. After specified gem is installed for the first time, Bundler will lock its version. To update it, you must use: [`bundler update`](#updating-gems---bundle-outdated-and-bundle-update) or/and modify its version in `Gemfile`. This file is created/updated automatically when you use some of Bundler's commands (e.g. `bundle install` or `bundle update`) and you should check it into version control. We will use Gemfile.lock from previous chapter as an example. GEM remote: https://rubygems.org/ specs: mini_portile2 (2.1.0) nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) pkg-config (1.1.7) PLATFORMS ruby DEPENDENCIES nokogiri (>= 1.4.0) BUNDLED WITH 1.12.5 Let's break it down: * `GEM` * `remote` - source of gems * `specs` - installed gems (with versions). We can see here that `mini_portile2` is dependency of `nokogiri` because it's beneath and indented * `PLATFORMS` - platform that is used in your application ([see more here](/gemfile/#PLATFORMS)). * `DEPENDENCIES` - gems defined in our Gemfile. * `BUNDLED WITH` - version of Bundler which was last used to change `Gemfile.lock` ## Executing Commands - **bundle exec** Let's see examples first: $ bundle exec rspec $ bundle exec rails s This will allow you to run command (`rspec` and `rails s` here) in current bundle context, making all gems in Gemfile available to `require` and use. *** To learn more about `bundle exec` command click [here](/command-reference/bundle-exec/). ## Updating Gems - **bundle outdated** and **bundle update** Now let's update some gems. With `bundle outdated` we can list installed gems with newer versions available: $ bundle outdated Fetching gem metadata from https://rubygems.org/ Fetching version metadata from https://rubygems.org/ Fetching dependency metadata from https://rubygems.org/ Resolving dependencies....... Outdated gems included in the bundle: * nokogiri (newest 1.6.8, installed 1.6.7.2) in group "default" You can also specify gems (`bundle outdated *gems`). We've got `nokogiri` locked on version 1.6.7.2. How can we update it? `bundle install` won't install newer version because it's locked in `Gemfile.lock` file. We must use `bundle update`. $ bundle update Fetching git://github.com/middleman/middleman-syntax.git Fetching gem metadata from https://rubygems.org/ Fetching version metadata from https://rubygems.org/ Fetching dependency metadata from https://rubygems.org/ Resolving dependencies..... Installing nokogiri 1.6.8 (was 1.6.7.2) with native extensions Using i18n 0.7.0 ... (and more) Bundle updated! Using `bundle update` without any argument will try to update every gem to newest available version (restrained by `Gemfile`). To update specific gems, use `bundle update *gems` *** To learn more about `bundle outdated` command click [here](/command-reference/bundle-outdated/). To learn more about `bundle update` command click [here](/command-reference/bundle-update/). ## Troubleshooting ### Running `git bisect` in projects using Bundler See [Git Bisect Guide](/git_bisect). --- # How to manage dependencies with Bundler Source: https://guides.rubygems.org/dependency_management/ This guide explains how Bundler manages your application's dependencies, why `Gemfile.lock` matters, and how to share a consistent environment with other developers and deployment targets. ### Declaring dependencies You declare your dependencies in a file at the root of your application called `Gemfile`. It looks something like this: ~~~ruby source 'https://rubygems.org' gem 'rails', '8.1.3.1' gem 'rack-cache' gem 'nokogiri', '~> 1.19.4' ~~~ This `Gemfile` says a few things. First, it says that bundler should look for gems declared in the `Gemfile` at `https://rubygems.org` by default. If some of your gems need to be fetched from a private gem server, this default source can be overridden for those gems. Next, you declare a few dependencies: - on version `8.1.3.1` of `rails` - on any version of `rack-cache` - on a version of `nokogiri` that is `>= 1.19.4` but `< 1.20.0` Learn More: Gemfiles ### Installing dependencies After declaring your first set of dependencies, you tell bundler to go get them: ~~~ $ bundle install ~~~ Bundler will connect to `rubygems.org` (and any other sources that you declared) and find a list of all of the required gems that meet the requirements you specified. Because all of the gems in your `Gemfile` have dependencies of their own (and some of those have their own dependencies), running `bundle install` on the `Gemfile` above will install quite a few gems. If any of the needed gems are already installed, Bundler will use them. After installing any needed gems to your system, bundler writes a snapshot of all of the gems and versions that it installed to `Gemfile.lock`. ### Checking Your Code into Version Control As you develop your application, `Gemfile.lock` accumulates a record of the exact versions of all of the gems that you used the last time you know for sure that the application worked. Keep in mind that while your `Gemfile` lists only three gems (with varying degrees of version strictness), your application depends on dozens of gems, once you take into consideration all of the implicit requirements of the gems you depend on. See [The Day-to-day Workflow](#the-day-to-day-workflow) below for when to commit it. This is important: **the `Gemfile.lock` makes your application a single package of both your own code and the third-party code it ran the last time you know for sure that everything worked**. Specifying exact versions of the third-party code you depend on in your `Gemfile` would not provide the same guarantee, because gems usually declare a range of versions for their dependencies. The next time you run `bundle install` on the same machine, bundler will see that it already has all of the dependencies you need and skip the installation process. Do not check in the `.bundle` directory or any of the files inside it. Those files are specific to each particular machine and are used to persist installation options between runs of the `bundle install` command. If you have run `bundle cache`, the gems required by your bundle will be downloaded into `vendor/cache`. Bundler can run without connecting to the internet (or the RubyGems server) if all the gems you need are present in that folder and checked in to your source control. This is an **optional** step and not recommended due to the increase in size of your source control repository. ### Sharing Your Application With Other Developers When your co-developers (or you on another machine) check out your code, it will come with the exact versions of all the third-party code your application used on the machine that you last developed on (in the `Gemfile.lock`). When **they** run `bundle install`, bundler will find the `Gemfile.lock` and skip the dependency resolution step. Instead, it will install all of the same gems that you used on the original machine. In other words, you don't have to guess which versions of the dependencies you should install. In the example we've been using, even though `rack-cache` declares a dependency on `rack >= 0.4`, we know for sure it works with `rack 3.2.6`. Even if the Rack team releases `rack 3.2.7`, bundler will always install `3.2.6`, the exact version of the gem that we know works. This relieves a large maintenance burden from application developers because all machines always run the exact same third-party code. ### The Day-to-day Workflow Once the `Gemfile` and `Gemfile.lock` are in version control, the routine is short: - Add or change a dependency in the `Gemfile`, then run `bundle install`. - Commit the updated `Gemfile.lock` together with the `Gemfile`, so that everyone else installs the same versions you tested with. This applies to applications: code that is deployed or run directly, not consumed as a dependency by other software. If you are developing a library that other applications will depend on, do not commit `Gemfile.lock`. A library's lockfile is ignored by any application that depends on it, and locking your own development environment would narrow the range of dependency versions you actually exercise. Add `lockfile false` to the `Gemfile` (or pass `--no-lock` to `bundle install`) instead. See the [FAQs](/faqs) for the case of a gem's own development checkout, where the tradeoffs differ. - If `bundle install` reports a conflict between the `Gemfile` and the `Gemfile.lock`, update only the gems you changed: ~~~ $ bundle update rails puma ~~~ - Run `bundle update` with no arguments only when you intend to move every gem to the newest version your `Gemfile` allows. - On a deployment machine or in CI, enable deployment mode before installing: ~~~ $ bundle config set --local deployment true $ bundle install ~~~ Deployment mode requires an up-to-date `Gemfile.lock` and installs gems into `vendor/bundle` inside the application. Do not enable it on a development machine, where editing the `Gemfile` would then raise an error. ### Loading and Running Your Bundle Inside your application, load the bundled environment before requiring anything: ~~~ruby require 'bundler/setup' # require your gems as usual require 'nokogiri' ~~~ To run an executable that comes with a gem in your bundle, prefix it with `bundle exec`: ~~~ $ bundle exec rspec spec/models ~~~ Running the executable without `bundle exec` sometimes works, if it also happens to be installed on your system and pulls in no gems that conflict with your bundle. That is unreliable. It may stop working later, or on another machine. If you want a shortcut for a gem you run often, generate binstubs for it: ~~~ $ bundle binstubs rspec-core $ bin/rspec spec/models ~~~ The executables in `bin` are scoped to the bundle, and will always work. --- # How to update gems with Bundler Source: https://guides.rubygems.org/updating_gems/ ### Updating a Dependency Of course, at some point, you might want to update the version of a particular dependency your application relies on. For instance, you might want to update `rails` to `3.0.0` final. Importantly, just because you're updating one dependency, it doesn't mean you want to re-resolve all of your dependencies and use the latest version of everything. In our example, you only have three dependencies, but even in this case, updating everything can cause complications. To illustrate, the `rails 3.0.0.rc` gem depends on `actionpack 3.0.0.rc` gem, which depends on `rack ~> 1.2.1` (which means `>= 1.2.1` and `< 1.3.0`). The `rack-cache` gem depends on `rack >= 0.4`. Let's assume that the `rails 3.0.0` final gem also depends on `rack ~> 1.2.1`, and that since the release of `rails 3.0.0`, the Rack team released `rack 1.2.2`. If we naïvely update all of our gems in order to update Rails, we'll get `rack 1.2.2`, which satisfies the requirements of both `rails 3.0.0` and `rack-cache`. However, we didn't specifically ask to update `rack-cache`, which may not be compatible with `rack 1.2.2` (for whatever reason). And while an update from `rack 1.2.1` to `rack 1.2.2` probably won't break anything, similar scenarios can happen that involve much larger jumps. (see [1] below for a larger discussion) In order to avoid this problem, when you update a gem, bundler will not update a dependency of that gem if another gem still depends on it. In this example, since `rack-cache` still depends on `rack`, bundler will not update the `rack` gem. This ensures that updating `rails` doesn't inadvertently break `rack-cache`. Since `rails 3.0.0`'s dependency `actionpack 3.0.0` remains compatible with `rack 1.2.1`, bundler leaves it alone, and `rack-cache` continues to work even in the face of an incompatibility with `rack 1.2.2`. Since you originally declared a dependency on `rails 3.0.0.rc`, if you want to update to `rails 3.0.0`, simply update your `Gemfile` to `gem 'rails', '3.0.0'` and run: ~~~ $ bundle install ~~~ As described above, the `bundle install` command always does a conservative update, refusing to update gems (or their dependencies) that you have not explicitly changed in the `Gemfile`. This means that if you do not modify `rack-cache` in your `Gemfile`, bundler will treat it **and its dependencies** (`rack`) as a single, unmodifiable unit. If `rails 3.0.0` was incompatible with `rack-cache`, bundler will report a conflict between your snapshotted dependencies (`Gemfile.lock`) and your updated `Gemfile`. If you update your `Gemfile`, and your system already has all of the needed dependencies, bundler will transparently update the `Gemfile.lock` when you boot your application. For instance, if you add `mysql` to your `Gemfile`, and have already installed it in your system, you can boot your application without running `bundle install`, and bundler will persist the "last known good" configuration to the `Gemfile.lock` snapshot. This can come in handy when adding or updating gems with minimal dependencies (database drivers, `wirble`, `ruby-debug`). It will probably fail if you update gems with significant dependencies (`rails`), or that a lot of gems depend on (`rack`). If a transparent update fails, your application will fail to boot, and bundler will print out an error instructing you to run `bundle install`. ### Updating a Gem Without Modifying the Gemfile Sometimes, you want to update a dependency without modifying the Gemfile. For example, you might want to update to the latest version of `rack-cache`. Because you did not declare a specific version of `rack-cache` in the `Gemfile`, you might want to periodically get the latest version of `rack-cache`. To do this, you want to use the `bundle update` command: ~~~ $ bundle update rack-cache ~~~ This command will update `rack-cache` and its dependencies to the latest version allowed by the `Gemfile` (in this case, the latest version available). It will not modify any other dependencies. It will, however, update dependencies of other gems if necessary. For instance, if the latest version of `rack-cache` specifies a dependency on `rack >= 1.2.2`, bundler will update `rack` to `1.2.2` even though you have not asked bundler to update `rack`. If bundler needs to update a gem that another gem depends on, it will let you know after the update has completed. If you want to update every gem in the Gemfile to the latest possible versions, run: ~~~ $ bundle update ~~~ This will resolve dependencies from scratch, ignoring the `Gemfile.lock`. If you do this, keep `git reset --hard` and your test suite in your back pocket. Resolving all dependencies from scratch can have surprising results, especially if a number of the third-party packages you depend on have released new versions since you last did a full update. ## Notes [1] For instance, if a new version of a gem depended on `rack 2.0`, that gem would still satisfy the requirement of `rack-cache`, which declares `>= 0.4` as a dependency. Of course, you could argue that `rack-cache` is silly for depending on open-ended versions, but these situations exist (extensively) in the wild, and projects often find themselves between a rock and a hard place when deciding what version to depend on. Constrain the dependency too much (`rack =1.5.1`) and you make it hard to use your project in other compatible projects. Constrain it too little (`rack >= 1.0`) and a new release of Rack may break your code. Using dependencies like `rack ~> 1.5.2` and versioning code in a SemVer compliant way mostly solves this problem, but it assumes universal compliance. Since RubyGems has over 100,000 packages, this assumption simply doesn't hold in practice. --- # How to manage groups of gems Source: https://guides.rubygems.org/groups/ Grouping your dependencies allows you to perform operations on the entire group. ~~~ruby # These gems are in the :default group gem 'nokogiri' gem 'sinatra' gem 'wirble', group: :development group :test do gem 'faker' gem 'rspec' end group :test, :development do gem 'capybara' gem 'rspec-rails' end gem 'cucumber', group: [:cucumber, :test] ~~~ Configure bundler so that subsequent `bundle install` invocations will install all gems, except those in the listed groups. Gems in at least one non-excluded group will still be installed. ~~~ $ bundle config set --local without test development ~~~ Require the gems in particular groups, noting that gems outside of a named group are in the :default group ~~~ruby Bundler.require(:default, :development) ~~~ Require the default gems, plus the gems in a group named the same as the current Rails environment ~~~ruby Bundler.require(:default, Rails.env) ~~~ Restrict the groups of gems that you want to add to the load path. Only gems in these groups will be requireable. Note though that `Bundler.setup` can be called only once, all subsequent calls are no-op. In particular, since running a script through `bundle exec` already calls `Bundler.setup`, any later calls inside your user code will be ignored. In order to control the groups that are loaded by `bundle exec` you can use the `BUNDLE_WITH` and `BUNDLE_WITHOUT` configurations. ~~~ruby require 'bundler' Bundler.setup(:default, :ci) require 'nokogiri' ~~~ Learn More: Bundler.setup ## Optional groups and `BUNDLE_WITH` Mark a group as optional using `group :name, optional: true do` and then opt into installing an optional group with `bundle config set --local with name`. ## Grouping your dependencies You'll sometimes have groups of gems that only make sense in particular environments. For instance, you might develop your app (at an early stage) using SQLite but deploy it using `mysql2` or `pg`. In this example, you might not have MySQL or Postgres installed on your development machine and want bundler to skip it. To do this, you can group your dependencies: ~~~ruby source 'https://rubygems.org' gem 'rails', '3.2.2' gem 'rack-cache', require: 'rack/cache' gem 'nokogiri', '~> 1.4.2' group :development do gem 'sqlite3' end group :production do gem 'pg' end ~~~ Now, in development, you can instruct bundler to skip the `production` group: ~~~ $ bundle config set --local without production ~~~ Bundler stores the flag in `APP_ROOT/.bundle/config` and the next time you run `bundle install`, it will skip production gems. Similarly, when you require `bundler/setup`, Bundler will ignore gems in these groups. You can see all of the settings that Bundler saved there by running `bundle config`, which will also print out global settings (stored in `~/.bundle/config`) and settings set via environment variables. For more information on configuring Bundler, please see: [`bundle config`](/command-reference/bundle-config/) You can also specify which groups to automatically require through the parameters to `Bundler.require`. The `:default` group includes all gems not listed under any group. If you call `Bundler.require(:default, :development)`, bundler will `require` all the gems in the `:default` group as well as the gems in the `:development` group. By default, a Rails generated app calls `Bundler.require(:default, Rails.env)` in your `application.rb`, which links the groups in your `Gemfile` to the Rails environment. If you use other groups (not linked to a Rails environment), you can add them to the call to `Bundler.require` if you want them to be automatically required. Remember that you can always leave groups of gems out of `Bundler.require` and then require them manually using Ruby's `require` at the appropriate place in your app. You might do this because requiring a certain gem takes some time and you don't need it every time you boot your application. --- # How to install gems from git repositories Source: https://guides.rubygems.org/git/ This document is written for Bundler 2.1 or higher. Use `bundle config X Y` instead of `bundle config set X Y` if you are still using Bundler 2.0 or earlier, which were already deprecated. Bundler has the ability to install gems directly from git repositories. Installing a gem using git is as easy as adding a gem to your Gemfile. Note that because RubyGems lacks the ability to handle gems from git, any gems installed from a git repository will not show up in `gem list`. They will, however, be available after running `Bundler.setup`. Specify that a gem should come from a git repository with a .gemspec at its root ~~~ruby gem 'rack', git: 'https://github.com/rack/rack' ~~~ If there is no .gemspec at the root of a git repository, you must specify a version that bundler should use when resolving dependencies ~~~ruby gem 'nokogiri', '1.7.0.1', git: 'https://github.com/sparklemotion/nokogiri' ~~~ If the gem is located within a subdirectory of a git repository, you can use the `:glob` option to specify the location of its .gemspec ~~~ruby gem 'cf-copilot', git: 'https://github.com/cloudfoundry/copilot', glob: 'sdk/ruby/*.gemspec' ~~~ Specify that a git repository containing multiple .gemspec files should be treated as a gem source ~~~ruby git 'https://github.com/rails/rails.git' do gem 'railties' gem 'actionpack' gem 'activemodel' end ~~~ From the previous example, you may specify a particular ref, branch or tag ~~~ruby git 'https://github.com/rails/rails.git', ref: '4aded' do git 'https://github.com/rails/rails.git', branch: '5-0-stable' do git 'https://github.com/rails/rails.git', tag: 'v5.0.0' do ~~~ Specifying a ref, branch, or tag for a git repository specified inline works exactly the same way ~~~ruby gem 'nokogiri', git: 'https://github.com/sparklemotion/nokogiri.git', ref: '0bd839d' gem 'nokogiri', git: 'https://github.com/sparklemotion/nokogiri.git', tag: '2.0.1' gem 'nokogiri', git: 'https://github.com/sparklemotion/nokogiri.git', branch: 'rack-1.5' ~~~ Bundler can use HTTP(S), SSH, or git ~~~ruby gem 'rack', git: 'https://github.com/rack/rack.git' gem 'rack', git: 'git@github.com:rack/rack.git' gem 'rack', git: 'git://github.com/rack/rack.git' ~~~ Specify that the submodules from a git repository also should be expanded by bundler ~~~ruby gem 'rugged', git: 'git://github.com/libgit2/rugged.git', submodules: true ~~~ If you are getting your gems from a public GitHub repository, you can use the shorthand ~~~ruby gem 'rack', github: 'rack/rack' ~~~ If the repository name is the same as the GitHub account hosting it, you can omit it ~~~ruby gem 'rails', github: 'rails' ~~~ *NB:* This shorthand can only be used for public repos in Bundler version 1.x. Use HTTPS for read and write: ~~~ruby gem 'rails', git: 'https://github.com/rails/rails' ~~~ All of the usual `:git` options apply, like `:branch` and `:ref`. ~~~ruby gem 'rails', github: 'rails', ref: 'a9752dcfd15bcddfe7b6f7126f3a6e0ba5927c56' ~~~ There are analogous shortcuts for Bitbucket (`:bitbucket`) and GitHub Gists (`:gist`). The `:gist` value is the id from the gist's URL. ~~~ruby gem 'keystone', bitbucket: 'musicone/keystone' gem 'microg', gist: 'bf6b8689108da1b9c4ddbe7f2acdd26c' ~~~ A gist cannot contain directories, so a gem served from a gist keeps all of its files at the top level. Put the gemspec at the root of the gist and set `require_paths = ["."]` so ruby files are loaded from there: ~~~ruby Gem::Specification.new do |spec| spec.name = "microg" spec.version = "0.1.0" spec.authors = ["x-yuri"] spec.summary = "a micro gem" spec.files = ["microg.rb"] spec.require_paths = ["."] end ~~~ ## Custom git sources The `:github` shortcut used above is one of Bundler's built in git sources. Bundler comes with shortcuts for `:github`, `:gist`, and `:bitbucket`, but you can also add your own. If you're using GitHub Enterprise, Stash, or just have a custom git setup, create your own shortcuts by calling `git_source` before you use your custom option. Here's an example for Stash: ~~~ruby git_source(:stash){ |repo_name| "https://stash.corp.acme.pl/#{repo_name}.git" } gem 'rails', stash: 'forks/rails' ~~~ ## Security `http://` and `git://` URLs are insecure. A man-in-the-middle attacker could tamper with the code as you check it out, and potentially supply you with malicious code instead of the code you meant to check out. Because the `:github` shortcut uses a `git://` URL in Bundler 1.x versions, we recommend using HTTPS URLs or overriding the `:github` shortcut with your own HTTPS git source. ## Local Git Repos Bundler also allows you to work against a git repository locally instead of using the remote version. This can be achieved by setting up a local override: ~~~ $ bundle config set local.GEM_NAME /path/to/local/git/repository ~~~ For example, in order to use a local Rack repository, a developer could call: ~~~ $ bundle config set local.rack ~/Work/git/rack ~~~ and setup the git repo pointing to a branch: ~~~ruby gem 'rack', github: 'rack/rack', branch: 'master' ~~~ Now instead of checking out the remote git repository, the local override will be used. Similar to a path source, every time the local git repository changes, the changes will be automatically picked up by Bundler. This means a commit in the local git repo will update the revision in the `Gemfile.lock` to the local git repo revision. This requires the same attention as git submodules. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine. **Please note!** Bundler does many checks to ensure a developer won't work with invalid references. Particularly, **we force a developer to specify a branch in the `Gemfile` in order to use this feature**. If the branch specified in the `Gemfile` and the current branch in the local git repository do not match, Bundler will abort. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch. Finally, Bundler also ensures that the current revision in the `Gemfile.lock` exists in the local git repository. By doing this, Bundler forces you to fetch the latest changes in the remotes. If you do not want bundler to make these branch checks, you can override it by setting this option: ~~~ $ bundle config set disable_local_branch_check true ~~~ --- # How to develop multiple gems in one repository Source: https://guides.rubygems.org/monorepo/ Using path gems to develop a family of related gems side by side. Some projects outgrow a single gem. A library gains plugins, or a framework splits into components, and it becomes easier to develop the pieces together in one repository. Rust's Cargo and Python's uv call this arrangement a workspace. In Ruby the same workflow is built from Bundler's path source: each gem keeps its own directory and gemspec, and a shared Gemfile wires them together. Path gems --------- The `path:` option tells Bundler that a gem lives in a directory on the local file system instead of on a gem server: ~~~ruby gem "mygem", path: "gems/mygem" ~~~ Relative paths are resolved against the directory containing the Gemfile. The directory must contain the gem's `.gemspec`, or the `gem` entry must specify an explicit version. Bundler loads the gem's code straight from that directory, so edits take effect the next time the code is loaded, with no rebuild or reinstall step. `bundle install` records a path source in `Gemfile.lock` as a `PATH` block holding the relative path and the version from the gemspec: ~~~ PATH remote: gems/mygem specs: mygem (1.0.0) DEPENDENCIES mygem! ~~~ The `!` marks a dependency pinned to a source declared in the Gemfile. See [How Gemfile.lock works](/gemfile-lock) for the full format. A path source exists only in the Gemfile. A gemspec dependency can name nothing more than a gem and a version requirement, so a published gem cannot direct its users to a local directory. When a gem released from a monorepo is installed, its dependencies are resolved from a gem server like anyone else's. The path wiring is a development convenience that stays behind in the repository. One Gemfile for many gems ------------------------- A typical layout keeps each gem in its own directory, each with its own gemspec, and puts a single Gemfile at the root: ~~~ mygem/ ├── Gemfile ├── Rakefile └── gems/ ├── mygem/ │ ├── mygem.gemspec │ └── lib/ └── mygem-cli/ ├── mygem-cli.gemspec └── lib/ ~~~ The root Gemfile can list each gem individually, or use the block form of `path`, which scans subdirectories of the given directory for gemspecs: ~~~ruby source "https://rubygems.org" path "gems" do gem "mygem" gem "mygem-cli" end ~~~ One `bundle install` at the root resolves everything, and both gems land in the same `PATH` block of the lockfile: ~~~ PATH remote: gems specs: mygem (1.0.0) mygem-cli (1.0.0) mygem (~> 1.0) ~~~ An alternative is the [`gemspec` method](/gemfile#GEMSPEC) with its `:path` option, one call per gem: ~~~ruby source "https://rubygems.org" gemspec path: "gems/mygem" gemspec path: "gems/mygem-cli" ~~~ The difference is what comes along. A `gem` entry with `path:` adds only the gem itself. `gemspec path:` also pulls that gem's runtime dependencies into the default group and its development dependencies into the `:development` group, which is useful when the root bundle is the development environment for every gem in the repository. Gems that depend on each other ------------------------------ When one gem in the repository depends on another, the dependency is declared in the gemspec with an ordinary version constraint: ~~~ruby Gem::Specification.new do |s| s.name = "mygem-cli" # ... s.add_dependency "mygem", "~> 1.0" end ~~~ The division of labor follows [Gemfile and gemspec](/gemfile-and-gemspec). The gemspec states which released versions are compatible, and that constraint is what ships in the built gem. The Gemfile's path source decides where the dependency comes from during development, so Bundler satisfies the `mygem (~> 1.0)` requirement with the local copy rather than a release from rubygems.org. Because the dependency is pinned to its path source, versions on the gem server are never considered, and resolution fails outright if the local version stops matching the constraint. Releasing --------- Each gem is still packaged and published on its own. Run [`gem build` and `gem push`](/publishing), or the `rake release` task that `bundle gem` generates, inside each gem's directory. Repositories with many gems commonly add tasks to the root Rakefile that loop over the gem directories to build, tag, and push them together. Whether the gems share one version number or are versioned independently is a policy choice for the project. The constraints in the gemspecs are what keep a mixed set of released versions working together. Rails is the best-known Ruby monorepo. The [rails/rails](https://github.com/rails/rails) repository holds railties, activesupport, actionpack, and the other framework gems, each in its own directory with its own gemspec, all released with the same version number. The [ruby/rubygems](https://github.com/ruby/rubygems) repository develops RubyGems and Bundler side by side in the same way. --- # How to use Bundler with Ruby Source: https://guides.rubygems.org/bundler_setup/ Configure the load path so all dependencies in your Gemfile can be required ~~~ruby require 'bundler/setup' require 'nokogiri' ~~~ Only add gems from specified groups to the load path. If you want the gems in the default group, make sure to include it ~~~ruby require 'bundler' Bundler.setup(:default, :ci) require 'nokogiri' ~~~ Learn More: Groups ## Compatibility Ruby 2.0 and RubyGems 2.0 both require Bundler 1.3 or later. If you have questions about compatibility between Bundler and your system, please check the compatibility list. Learn More: Compatibility ## Setting Up Your Application to Use Bundler Bundler makes sure that Ruby can find all of the gems in the `Gemfile` (and all of their dependencies). If your app is a Rails app, your default application already has the code necessary to invoke bundler. For another kind of application (such as a Sinatra application), you will need to set up bundler before trying to require any gems. At the top of the first file that your application loads (for Sinatra, the file that calls `require 'sinatra'`), put the following code: ~~~ruby require 'bundler/setup' ~~~ This will automatically discover your `Gemfile` and make all of the gems in your `Gemfile` available to Ruby (in technical terms, it puts the gems "on the load path"). Now that your code is available to Ruby, you can require the gems that you need. For instance, you can `require 'sinatra'`. If you have a lot of dependencies, you might want to say "require all of the gems in my `Gemfile`". To do this, put the following code immediately following `require 'bundler/setup'`: ~~~ruby Bundler.require(:default) ~~~ For our example Gemfile, this line is exactly equivalent to: ~~~ruby require 'rails' require 'rack-cache' require 'nokogiri' ~~~ Astute readers will notice that the correct way to require the `rack-cache` gem is `require 'rack/cache'`, not `require 'rack-cache'`. To tell bundler to use `require 'rack/cache'`, update your Gemfile: ~~~ruby source 'https://rubygems.org' gem 'rails', '5.0.0' gem 'rack-cache', require: 'rack/cache' gem 'nokogiri', '~> 1.4.2' ~~~ For such a small `Gemfile`, we'd advise you to skip `Bundler.require` and just require the gems by hand (especially given the need to put in a `:require` directive in the `Gemfile`). For much larger `Gemfile`s, using `Bundler.require` allows you to skip repeating a large stack of requirements. --- # How to use Bundler in a single-file Ruby script Source: https://guides.rubygems.org/bundler_in_a_single_file_ruby_script/ To use Bundler in a single-file script, add `require 'bundler/inline'` at the top of your Ruby file. Then, use the `gemfile` method to declare any gem sources and gems that you need. Here's an example: ~~~ ruby require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'json', require: false gem 'nap', require: 'rest' gem 'cocoapods', '~> 0.34.1' end puts 'Gems installed and loaded!' puts "The nap gem is at version #{REST::VERSION}" ~~~ To run this script, including installing any missing gems, save the script into a file (for example, `bundler_inline_example.rb`) and then run the file with the command `ruby bundler_inline_example.rb`. Running the script will automatically install any missing gems, require the gems you listed, and then run your code. --- # How to deploy bundled applications Source: https://guides.rubygems.org/deploying/ Before deploying an app that uses Bundler, add your `Gemfile` and `Gemfile.lock` to source control, but ignore the `.bundle` folder, which is specific to each machine. ~~~ $ echo ".bundle" >> .gitignore $ git add Gemfile Gemfile.lock .gitignore $ git commit -m "Add Bundler support" ~~~ After updating to the latest code, install your bundle to the `vendor/bundle` directory, ensuring all your dependencies are met. ~~~ $ bundle install --deployment ~~~ Start your application servers as usual, and your application will use your bundled environment with the exact same gems you use in development. If you have run `bundle package`, the cached gems will be used automatically. Learn More: Packing ### After deploying Make sure to use `bundle exec` to run any executables from gems in the bundle ~~~ $ bundle exec rake db:setup ~~~ Alternatively, you can run `bundle binstubs GEM_NAME` (or `bundle binstubs --all`) to generate executable binaries that can be used instead of `bundle exec`. Learn More: Executables ### Heroku When you deploy to Heroku, Bundler will be run automatically as long as a Gemfile is present. If you check in your Gemfile.lock, Heroku will run `bundle install --deployment`. If you want to exclude certain groups using the `--without` option, you need to use `heroku config`. ~~~ $ heroku config:set BUNDLE_WITHOUT="test development" --app app_name ~~~ Heroku Bundler Documentation ## Deploying Your Application When you run `bundle install`, bundler will (by default), install your gems to your system repository of gems. This means that they will show up in `gem list`. Additionally, if you are developing a number of applications, you will not need to download and install gems in common for each application. This is nice for development, but somewhat problematic for deployment. In a deployment scenario, the Unix user you deploy with may not have access to install gems to a system location. Even if the user does (or you use `sudo`), the user that boots the application may not have access to them. For instance, Passenger runs its Ruby subprocesses with the user `nobody`, a somewhat restricted user. The tradeoffs in a deployment environment lean more heavily in favor of isolation (even at the cost of a somewhat slower deploy-time `bundle install` when some third-party dependencies have changed). As a result, bundler comes with a `--deployment` flag that encapsulates the best practices for using bundler in a deployment environment. These practices are based on significant feedback we have received during the development of bundler, as well as a number of bug reports that mostly reflected a misunderstanding of how to best configure bundler for deployment. The `--deployment` flag adds the following defaults: - Instead of installing gems to the system location, bundler will install gems to `vendor/bundle` inside your application. Bundler will transparently remember this location when you invoke it inside your application (with `Bundler.setup` and `Bundler.require`). - Bundler will not use gems already installed to your system, even if they exist. - If you have run `bundle pack`, checked in the `vendor/cache` directory, and do not have any git gems, Bundler will not contact the internet while installing your bundle. - Bundler will require a `Gemfile.lock` snapshot, and fail if you did not provide one. - Bundler will not transparently update your `Gemfile.lock` if it is out of date with your `Gemfile` By defaulting the bundle directory to `vendor/bundle`, and installing your bundle as part of your deployment process, you can be sure that the same Unix user that checked out your application also installed the third-party code your application needs. This means that if Passenger (or Unicorn) can see your application, it can also see its dependencies. The `--deployment` flag requires an up-to-date `Gemfile.lock` to ensure that the testing you have done (in development and staging) actually reflects the code you put into production. You can run `bundle check` before deploying your application to make sure that your `Gemfile.lock` is up-to-date. Note that it will always be up-to-date if you have run `bundle install`, successfully booted your application (or run your tests) since the last time you changed your `Gemfile`. --- # Name your gem Source: https://guides.rubygems.org/name-your-gem/ Our recommendation on the use of "_" and "-" in your gem's name. Here are some examples of our recommendations for naming gems: Gem name | Require statement | Main class or module ---------------------- | -------------------------------- | ----------------------- `ruby_parser` | `require 'ruby_parser'` | `RubyParser` `rdoc-data` | `require 'rdoc/data'` | `RDoc::Data` `net-http-persistent` | `require 'net/http/persistent'` | `Net::HTTP::Persistent` `net-http-digest_auth` | `require 'net/http/digest_auth'` | `Net::HTTP::DigestAuth` The main goal of these recommendations is to give the user some clue about how to require the files in your gem. Following these conventions also lets Bundler require your gem with no extra configuration. If you publish a gem on [rubygems.org][rubygems] it may be removed if the name is objectionable, violates intellectual property or the contents of the gem meet these criteria. You can report such a gem to [support@rubygems.org](mailto:support@rubygems.org) via email. [rubygems]: https://rubygems.org Use underscores for multiple words ---------------------------------- If a class or module has multiple words, use underscores to separate them. This matches the file the user will require, making it easier for the user to start using your gem. Use dashes for extensions ------------------------- If you're adding functionality to another gem, use a dash. This usually corresponds to a `/` in the require statement (and therefore your gem's directory structure) and a `::` in the name of your main class or module. Mix underscores and dashes appropriately ---------------------------------------- If your class or module has multiple words and you're also adding functionality to another gem, follow both of the rules above. For example, [`net-http-digest_auth`][digest-gem] adds [HTTP digest authentication][digest-standard] to `net/http`. The user will `require 'net/http/digest_auth'` to use the extension (in class `Net::HTTP::DigestAuth`). [digest-gem]: https://rubygems.org/gems/net-http-digest_auth [digest-standard]: https://tools.ietf.org/html/rfc2617 Don't use UPPERCASE letters --------------------------- OS X and Windows have case-insensitive filesystems by default. Users may mistakenly require files from a gem using uppercase letters which will be non-portable if they move it to a non-windows or OS X system. While this will mostly be a newbie mistake we don't need to be confusing them more than necessary. Credits ------- This guide was expanded from [How to Name Gems][how-to-name-gems] by Eric Hodel. [how-to-name-gems]: https://web.archive.org/web/20130821183311/https://blog.segment7.net/2010/11/15/how-to-name-gems --- # Patterns Source: https://guides.rubygems.org/patterns/ Common practices to make your gem users' and other developers' lives easier. This page covers conventions for naming and structuring a gem and for loading its code. Guidance that used to live here has moved: for version numbering, prerelease versions, and dependency constraints see [Versioning and compatibility](/versioning), and for where to declare runtime and development dependencies see [Gemfile and gemspec](/gemfile-and-gemspec). * [Consistent naming](#consistent-naming) * [Loading code](#loading-code) Consistent naming ----------------- > There are only two hard things in Computer Science: cache invalidation and naming things. > -[Phil Karlton](https://martinfowler.com/bliki/TwoHardThings.html) ### File names Be consistent with how the files of your gem are named. This is the layout `bundle gem hola --exe` generates, with the support files trimmed: % tree hola hola ├── Gemfile ├── Rakefile ├── exe │ └── hola ├── hola.gemspec ├── lib │ ├── hola │ │ └── version.rb │ └── hola.rb └── test ├── test_helper.rb └── test_hola.rb The executable in `exe` and the primary file in `lib` are named after the gem. A developer can easily jump in and call `require 'hola'` with no problems. Everything beyond the primary file lives in a directory with the gem's name, like `lib/hola/version.rb`, for reasons covered in the [Loading code](#loading-code) section below. ### Naming your gem Naming your gem is important. Before you pick a name for your gem, do a quick search on [RubyGems.org](https://rubygems.org) and [GitHub](https://github.com/search) to see if someone else has taken it. Every published gem must have a unique name. Be sure to read our [naming recommendations](/name-your-gem) when you've found a name you like. Loading code ------------ At its core, RubyGems exists to help you manage Ruby's `$LOAD_PATH`, which is how the `require` statement picks up new code. There's several things you can do to make sure you're loading code the right way. ### Respect the global load path When packaging your gem files, you need to be careful of what is in your `lib` directory. Every gem you have installed gets its `lib` directory appended onto your `$LOAD_PATH`. This means any file on the top level of the `lib` directory could get required. For example, let's say we have a `foo` gem with the following structure: . └── lib ├── foo │ └── cgi.rb ├── erb.rb ├── foo.rb └── set.rb This might seem harmless since your custom `erb` and `set` files are within your gem. However, this is not harmless, anyone who requires this gem will not be able to bring in the [ERB](https://docs.ruby-lang.org/en/master/ERB.html) or [Set](https://docs.ruby-lang.org/en/master/Set.html) classes provided by Ruby's standard library. The best way to get around this is to keep files in a different directory under `lib`. The usual convention is to be consistent and put them in the same folder name as your gem's name, for example `lib/foo/cgi.rb`. ### Requiring files relative to each other Gems should not have to use `__FILE__` to bring in other Ruby files in your gem. Code like this is surprisingly common in gems: require File.join( File.dirname(__FILE__), "foo", "bar") Or: require File.expand_path(File.join( File.dirname(__FILE__), "foo", "bar")) The fix is simple, just require the file relative to the load path: require 'foo/bar' Or use require_relative: require_relative 'foo/bar' The [make your own gem](/make-your-own-gem) guide has a great example of this behavior in practice, including a working test suite. The code for that gem is [on GitHub](https://github.com/qrush/hola) as well. ### Mangling the load path Gems should not change the `$LOAD_PATH` variable. RubyGems manages this for you. Code like this should not be necessary: lp = File.expand_path(File.dirname(__FILE__)) unless $LOAD_PATH.include?(lp) $LOAD_PATH.unshift(lp) end Or: __DIR__ = File.dirname(__FILE__) $LOAD_PATH.unshift __DIR__ unless $LOAD_PATH.include?(__DIR__) || $LOAD_PATH.include?(File.expand_path(__DIR__)) When RubyGems activates a gem, it adds your package's `lib` folder to the `$LOAD_PATH` ready to be required normally by another lib or application. It is safe to assume you can then `require` any file in your `lib` folder. ### Don't use `gem` from within your gem You may have seen some code like this around to make sure a specific version of a gem is activated before requiring it: gem "extlib", ">= 1.0.8" require "extlib" Gems **should not** do this. Declare the requirement in the gemspec instead, so the resolver can weigh it together with every other gem's requirements, and let RubyGems handle activating the right version. Applications control their dependency versions with [Bundler](/getting_started) rather than `gem` calls. Credits ------- Several sources were used for content for this guide: * [Rubygems Good Practice](https://yehudakatz.com/2009/07/24/rubygems-good-practice/) * [Gem Packaging: Best Practices](https://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices) --- # Gems with Extensions Source: https://guides.rubygems.org/gems-with-extensions/ Creating a gem that includes an extension that is built at install time. Many gems use extensions to wrap libraries that are written in C with a ruby wrapper. Examples include [nokogiri][nokogiri] which wraps [libxml2 and libxslt](http://www.xmlsoft.org), [pg](https://rubygems.org/gems/pg) which is an interface to the [PostgreSQL database](https://www.postgresql.org) and the [mysql](https://rubygems.org/gems/mysql) and [mysql2](https://rubygems.org/gems/mysql2) gems which provide an interface to the [MySQL database](https://www.mysql.com). Creating a gem that uses an extension involves several steps. This guide will focus on what you should put in your gem specification to make this as easy and maintainable as possible. The extension in this guide will wrap `malloc()` and `free()` from the C standard library. Extensions don't have to be written in C. This guide uses C for its main example, but you can also write extensions in [Rust](#rust-extensions); see the Rust Extensions section below. Gem layout ---------- Every gem should start with a Rakefile which contains the tasks needed by developers to work on the gem. The files for the extension should go in the `ext/` directory in a directory matching the extension's name. For this example we'll use "my_malloc" for the name. Some extensions will be partially written in C and partially written in ruby. If you are going to support multiple languages, such as C and Java extensions, put the ruby files that are specific to the C extension in a `lib/` directory under the extension's directory (`ext/my_malloc/lib/` here), not in the top-level `lib/` directory. Rakefile ext/my_malloc/extconf.rb # extension configuration ext/my_malloc/my_malloc.c # extension source ext/my_malloc/lib/my_malloc/helper.rb # ruby code for the C extension lib/my_malloc.rb # generic features When the extension is built the files in `ext/my_malloc/lib/` will be installed into the `lib/` directory for you. extconf.rb ---------- The extconf.rb configures a Makefile that will build your extension. The extconf.rb must check for the necessary functions, macros and shared libraries your extension depends upon. The extconf.rb must exit with an error if any of these are missing. Here is an extconf.rb that checks for `malloc()` and `free()` and creates a Makefile that will install the built extension at `lib/my_malloc/my_malloc.so`: require "mkmf" abort "missing malloc()" unless have_func "malloc" abort "missing free()" unless have_func "free" create_makefile "my_malloc/my_malloc" See the [mkmf documentation][mkmf.rb] and [extension.rdoc][extension.rdoc] for further information about creating an extconf.rb and for documentation on these methods. C Extension ----------- The C extension that wraps `malloc()` and `free()` goes in `ext/my_malloc/my_malloc.c`. Here's the listing: #includeThe Specification class contains the information for a gem. Typically defined in a .gemspec file or a Rakefile, and looks like this:
Gem::Specification.new do |s| s.name = 'example' s.version = '0.1.0' s.licenses = ['MIT'] s.summary = "This is an example!" s.description = "Much longer explanation of the example!" s.authors = ["Ruby Coder"] s.email = 'rubycoder@example.com' s.files = ["lib/example.rb"] s.homepage = 'https://rubygems.org/gems/example' s.metadata = { "source_code_uri" => "https://github.com/example/example" } end
Starting in RubyGems 2.0, a Specification can hold arbitrary metadata. See metadata for restrictions on the format and size of metadata items you may add to a specification.
Specifications must be deterministic, as in the example above. For instance, you cannot define attributes conditionally:
# INVALID: do not do this. unless RUBY_ENGINE == "jruby" s.extensions << "ext/example/extconf.rb" end## Required gemspec attributes * [authors=](#authors=) * [files](#files) * [name](#name) * [summary](#summary) * [version](#version) ## Recommended gemspec attributes * [description](#description) * [email](#email) * [homepage](#homepage) * [license=](#license=) * [licenses=](#licenses=) * [metadata](#metadata) * [required_ruby_version](#required_ruby_version) ## Read-only attributes * [extensions_dir](#extensions_dir) * [rubygems_version](#rubygems_version) ## Optional gemspec attributes * [add_dependency](#add_dependency) * [add_development_dependency](#add_development_dependency) * [author=](#author=) * [bindir](#bindir) * [cert_chain](#cert_chain) * [executables](#executables) * [extensions](#extensions) * [extra_rdoc_files](#extra_rdoc_files) * [platform=](#platform=) * [post_install_message](#post_install_message) * [rdoc_options](#rdoc_options) * [require_paths=](#require_paths=) * [required_ruby_version=](#required_ruby_version=) * [required_rubygems_version](#required_rubygems_version) * [required_rubygems_version=](#required_rubygems_version=) * [requirements](#requirements) * [signing_key](#signing_key) # Required gemspec attributes ## authors=(`value`)
A list of authors for this gem.
Alternatively, a single author can be specified by assigning a string to spec.author
Usage:
spec.authors = ['John Jones', 'Mary Smith']## files
Files included in this gem. You cannot append to this accessor, you must assign to it.
Only add files you can require to this list, not directories, etc.
Directories are automatically stripped from this list when building a gem, other non-files cause an error.
Usage:
require 'rake' spec.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*'].to_a # or without Rake... spec.files = Dir['lib/**/*.rb'] + Dir['bin/*'] spec.files += Dir['[A-Z]*'] spec.files.reject! { |fn| fn.include? "CVS" }## name
This gem’s name.
Usage:
spec.name = 'rake'## summary
A short summary of this gem’s description. Displayed in gem list -d.
The description should be more detailed than the summary.
Usage:
spec.summary = "This is a small summary of my gem"## version
This gem’s version.
The version string can contain numbers and periods, such as 1.0.0. A gem is a ‘prerelease’ gem if the version has a letter in it, such as 1.0.0.pre.
Usage:
spec.version = '0.4.1'# Recommended gemspec attributes ## description
A long description of this gem
The description should be more detailed than the summary but not excessively long. A few paragraphs is a recommended length with no examples or formatting.
Usage:
spec.description = <<~EOF Rake is a Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax. EOF## email
A contact email address (or addresses) for this gem
Usage:
spec.email = 'john.jones@example.com' spec.email = ['jack@example.com', 'jill@example.com']## homepage
The URL of this gem’s home page
Usage:
spec.homepage = 'https://github.com/ruby/rake'## license=(`o`)
The license for this gem.
The license must be no more than 64 characters, and should be a single SPDX license identifier from spdx.org/licenses/. Ideally, you should pick one that is OSI (Open Source Initiative) opensource.org/licenses/ approved.
The most commonly used OSI-approved licenses are MIT and Apache-2.0. GitHub also provides a license picker at choosealicense.com/.
The full text of the license should be inside of the gem (at the top level) when you build it.
RubyGems validates the license against the SPDX license list when you run gem build and warns about unknown or deprecated identifiers. An identifier may carry a trailing + (this version or any later version) and a license exception joined with WITH, for example Apache-2.0 WITH LLVM-exception.
Compound SPDX license expressions such as MIT OR Apache-2.0 are not currently supported. RubyGems treats the whole string as a single identifier and warns that it is invalid. For a gem available under more than one license, set each license as a separate entry with licenses=.
For a license that has no SPDX identifier, use Nonstandard, or LicenseRef-<idstring> where idstring is the name of the file containing the license text.
You should specify a license for your gem so that people know how they are permitted to use it and any restrictions you’re placing on it. Not specifying a license means all rights are reserved; others have no right to use the code for any purpose.
Usage:
spec.license = 'MIT'## licenses=(`licenses`)
The license(s) for the library.
Each entry must be a single SPDX license identifier, no more than 64 characters. Entries are validated independently, so a compound expression such as MIT OR Apache-2.0 is not valid as an entry. Listing the identifiers as separate array elements is currently the only way RubyGems supports declaring a dual- or multi-licensed gem.
Note that the array itself does not state how the licenses combine. Include the full text of each license in the gem and describe the exact terms there.
See license= for more discussion
Usage:
spec.licenses = ['MIT', 'GPL-2.0-only']## metadata
The metadata holds extra data for this gem that may be useful to other consumers and is settable by gem authors.
Metadata items have the following restrictions:
The metadata must be a Hash object
All keys and values must be Strings
Keys can be a maximum of 128 bytes and values can be a maximum of 1024 bytes
All strings must be UTF-8, no binary data is allowed
You can use metadata to specify links to your gem’s homepage, codebase, documentation, wiki, mailing list, issue tracker and changelog.
s.metadata = { "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", "homepage_uri" => "https://bestgemever.example.io", "mailing_list_uri" => "https://groups.example.com/bestgemever", "source_code_uri" => "https://example.com/user/bestgemever", "wiki_uri" => "https://example.com/user/bestgemever/wiki", "funding_uri" => "https://example.com/donate" }
These links will be used on your gem’s page on rubygems.org and must pass validation against following regex.
%r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}
## required_ruby_version
The version of Ruby required by this gem
Usage:
spec.required_ruby_version = '>= 2.7.0'# Read-only attributes ## extensions_dir
The path where this gem installs its extensions.
## rubygems_versionThe version of RubyGems used to create this gem.
# Optional gemspec attributes ## add_dependency(`gem`, `*requirements`)Adds a runtime dependency named gem with requirements to this gem.
Usage:
spec.add_dependency 'example', '>= 1.1.4', '< 2'Also known as: **add_runtime_dependency** ## add_development_dependency(`gem`, `*requirements`)
Adds a development dependency named gem with requirements to this gem.
Usage:
spec.add_development_dependency 'example', '>= 1.1.4', '< 2'
Development dependencies aren’t installed by default and aren’t activated when a gem is required.
## author=(`o`)Singular (alternative) writer for authors
Usage:
spec.author = 'John Jones'## bindir
The path in the gem for executable scripts. Usually ‘exe’
Usage:
spec.bindir = 'exe'## cert_chain
The certificate chain used to sign this gem. See Gem::Security for details.
## executablesExecutables included in the gem.
For example, the rake gem has rake as an executable. You don’t specify the full path (as in bin/rake); all application-style files are expected to be found in bindir. These files must be executable Ruby files. Files that use bash or other interpreters will not work.
Executables included may only be ruby scripts, not scripts for other languages or compiled binaries.
Usage:
spec.executables << 'rake'## extensions
Extensions to build when installing the gem, specifically the paths to extconf.rb-style files used to compile extensions.
These files will be run when the gem is installed, causing the C (or whatever) code to be compiled on the user’s machine.
Usage:
spec.extensions << 'ext/rmagic/extconf.rb'
See Gem::Ext::Builder for information about writing extensions for gems.
## extra_rdoc_filesExtra files to add to RDoc such as README or doc/examples.txt
When the user elects to generate the RDoc documentation for a gem (typically at install time), all the library files are sent to RDoc for processing. This option allows you to have some non-code files included for a more complete set of documentation.
Usage:
spec.extra_rdoc_files = ['README', 'doc/user-guide.txt']## platform=(`platform`)
The platform this gem runs on.
This is usually Gem::Platform::RUBY or Gem::Platform::CURRENT.
Most gems contain pure Ruby code; they should simply leave the default value in place. Some gems contain C (or other) code to be compiled into a Ruby “extension”. The gem should leave the default value in place unless the code will only compile on a certain type of system. Some gems consist of pre-compiled code (“binary gems”). It’s especially important that they set the platform attribute appropriately. A shortcut is to set the platform to Gem::Platform::CURRENT, which will cause the gem builder to set the platform to the appropriate value for the system on which the build is being performed.
If this attribute is set to a non-default value, it will be included in the filename of the gem when it is built such as: nokogiri-1.6.0-x86-mingw32.gem
Usage:
spec.platform = Gem::Platform.local## post_install_message
A message that gets displayed after the gem is installed.
Usage:
spec.post_install_message = "Thanks for installing!"## rdoc_options
Specifies the rdoc options to be used when generating API documentation.
Usage:
spec.rdoc_options << '--title' << 'Rake -- Ruby Make' << '--main' << 'README' << '--line-numbers'## require_paths=(`val`)
Paths in the gem to add to $LOAD_PATH when this gem is activated. If you have an extension you do not need to add "ext" to the require path, the extension build process will copy the extension files into “lib” for you.
The default value is "lib"
Usage:
# If all library files are in the root directory... spec.require_paths = ['.']## required_ruby_version=(`req`)
The version of Ruby required by this gem. The ruby version can be specified to the patch-level:
$ ruby -v -e 'p Gem.ruby_version' ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0] #<Gem::Version "2.0.0.247">
Prereleases can also be specified.
Usage:
# This gem will work with 1.8.6 or greater... spec.required_ruby_version = '>= 1.8.6' # Only with final releases of major version 2 where minor version is at least 3 spec.required_ruby_version = '~> 2.3' # Only prereleases or final releases after 2.6.0.preview2 spec.required_ruby_version = '> 2.6.0.preview2' # This gem will work with 2.3.0 or greater, including major version 3, but lesser than 4.0.0 spec.required_ruby_version = '>= 2.3', '< 4'## required_rubygems_version
The RubyGems version required by this gem
## required_rubygems_version=(`req`)The RubyGems version required by this gem
## requirementsLists the external (to RubyGems) requirements that must be met for this gem to work. It’s simply information for the user.
Usage:
spec.requirements << 'libmagick, v6.0' spec.requirements << 'A good graphics card'## signing_key
The key used to sign this gem. See Gem::Security for details.
--- # RubyGems.org API Source: https://guides.rubygems.org/rubygems-org-api/ Details on interacting with RubyGems.org over HTTP. Most endpoints are under API v1. API v2 covers lookups scoped to one specific gem version. > NOTE: The API is a work in progress, and [can use your help!](https://github.com/rubygems/rubygems.org) > RubyGems itself and the > [RubyGems gem](https://github.com/rubygems/rubygems) use the API to push gems, > add owners, and more. * [API Authorization](#api-authorization): How to authenticate with RubyGems.org * [Rate Limits](#rate-limits) * [Gem Methods](#gem-methods): Query or create gems to be hosted * [Gem Version Methods](#gem-version-methods): Query for information about versions of a particular gem * [Gem Download Methods](#gem-download-methods): Query for download statistics * [Owner Methods](#owner-methods): Manage owners for gems * [Profile Methods](#profile-methods): Query for user information * [Webhook Methods](#webhook-methods): Manage notifications for when gems are pushed * [Activity Methods](#activity-methods): Query for information about site-wide activity * [Misc Methods](#misc-methods): Various other interactions with the site API Authorization ----------------- Some API calls require an Authorization header. To create or view existing API keys, click on your username when logged in to [RubyGems.org](https://rubygems.org), 'Settings', and then 'API Keys'. Here's an example of using an API key: $ curl -H 'Authorization:YOUR_API_KEY' \ https://rubygems.org/api/v1/some_api_call.json If you are using Multi-factor authentication, you will need to provide one-time passcode in the `OTP` header. Here's an example of using your API key with a OTP: $ curl -H 'Authorization:YOUR_API_KEY' \ -H 'OTP:YOUR_ONE_TIME_PASSCODE' \ https://rubygems.org/api/v1/some_api_call.json Each key carries a set of scopes, and a call fails if the key lacks the scope it needs. Pushing a gem, for example, requires `push_rubygem`. See [API key scopes](/api-key-scopes) for the full list. Ruby Library ------------ You can also interact with RubyGems.org using Ruby. The [gems](https://rubygems.org/gems/gems) client provides a Ruby interface to all the resources listed below. This library has [full documentation](https://rubydoc.info/gems/gems) that includes some basic usage examples in the README. You can install the library with the command: gem install gems Rate Limits ----------- Please see [RubyGems.org ratelimits](/rubygems-org-rate-limits) Gem Methods ----------- ### GET - `/api/v1/gems/[GEM NAME].(json|yaml)` Returns some basic information about the given gem. See below an example response for the gem "rails" in JSON format: $ curl https://rubygems.org/api/v1/gems/rails.json { "name": "rails", "downloads": 769153204, "version": "8.1.3.1", "version_created_at": "2026-07-29T15:02:41.060Z", "version_downloads": 78333, "platform": "ruby", "authors": "David Heinemeier Hansson", "info": "Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity.", "licenses": ["MIT"], "metadata": { "changelog_uri": "https://github.com/rails/rails/releases/tag/v8.1.3.1", "bug_tracker_uri": "https://github.com/rails/rails/issues", "source_code_uri": "https://github.com/rails/rails/tree/v8.1.3.1", "rubygems_mfa_required": "true" }, "yanked": false, "sha": "ccd11a36bfc171bf9c66d585d14c0ece91c0c9dde840aae60c0118d6f5c9c52a", "spec_sha": "5b60af49df6edf722925a85d144f1118abda22485a820da2c516e97cab8347b8", "project_uri": "https://rubygems.org/gems/rails", "gem_uri": "https://rubygems.org/gems/rails-8.1.3.1.gem", "homepage_uri": "https://rubyonrails.org", "wiki_uri": null, "documentation_uri": "https://api.rubyonrails.org/v8.1.3.1/", "mailing_list_uri": "https://discuss.rubyonrails.org/c/rubyonrails-talk", "source_code_uri": "https://github.com/rails/rails/tree/v8.1.3.1", "bug_tracker_uri": "https://github.com/rails/rails/issues", "changelog_uri": "https://github.com/rails/rails/releases/tag/v8.1.3.1", "funding_uri": null, "dependencies": { "development": [], "runtime": [ { "name": "actioncable", "requirements": "= 8.1.3.1" }, { "name": "actionmailbox", "requirements": "= 8.1.3.1" }, { "name": "actionmailer", "requirements": "= 8.1.3.1" }, ... ] } } ### GET - `/api/v1/search.(json|yaml)?query=[YOUR QUERY]` Submit a search to RubyGems.org for active gems, just like a search query on the site. Returns an array of the JSON or YAML representation of gems that match. $ curl 'https://rubygems.org/api/v1/search.json?query=cucumber' $ curl 'https://rubygems.org/api/v1/search.yaml?query=cucumber' The results are paginated so the API call will return only the first 30 matched gems. To get subsequent results, use the page query parameter until an empty response is received. $ curl 'https://rubygems.org/api/v1/search.json?query=cucumber&page=2' ### GET - `/api/v1/search/autocomplete?query=[YOUR QUERY]` Returns an array of gem names matching the query, for populating a search box. $ curl 'https://rubygems.org/api/v1/search/autocomplete?query=nokogiri' ["nokogiri","nokogiri-diff","nokogiri-happymapper","nokogiri-styles", ...] ### GET - `/api/v1/gems.(json|yaml)` List all gems that you own. Returns an array of the JSON or YAML representation of gems you own. $ curl -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ https://rubygems.org/api/v1/gems.json ### POST - `/api/v1/gems` Submit a gem to RubyGems.org. Must post a built RubyGem in the request body. $ curl --data-binary @gemcutter-0.2.1.gem \ -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ https://rubygems.org/api/v1/gems Successfully registered gem: gemcutter (0.2.1) ### DELETE - `/api/v1/gems/yank` Remove a gem from RubyGems.org's index. Platform is optional. $ curl -X DELETE -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -d 'gem_name=bills' -d 'version=0.0.1' \ -d 'platform=x86-darwin-10' \ https://rubygems.org/api/v1/gems/yank Successfully deleted gem: bills (0.0.1) ### GET - `/api/v1/gems/[GEM NAME]/reverse_dependencies.json` List dependants of the specified gem. This is all the dependants whose latest version depend on the particular gem. Returns an array that includes names of the dependant gems. Pass `only=runtime` or `only=development` to restrict the result to that dependency type. Both types are returned by default. $ curl https://rubygems.org/api/v1/gems/shoulda/reverse_dependencies.json [ "jeweler", "rubigen", "verhoeff", "vanilla", "soup", ... ] Gem Version Methods ------------------- ### GET - `/api/v1/versions/[GEM NAME].(json|yaml)` Returns an array of gem version details like the below: $ curl https://rubygems.org/api/v1/versions/coulda.json [ { "authors": "Evan David Light", "built_at": "2011-08-08T04:00:00.000Z", "created_at": "2011-08-08T21:23:40.254Z", "description": "Behaviour Driven Development derived from Cucumber but as an internal DSL with methods for reuse", "downloads_count": 9676, "metadata": { "homepage_uri": "http://coulda.tiggerpalace.com" }, "number": "0.7.1", "summary": "Test::Unit-based acceptance testing DSL", "platform": "ruby", "rubygems_version": ">= 0", "ruby_version": null, "prerelease": false, "licenses": null, "requirements": null, "sha": "777c3a7ed83e44198b0a624976ec99822eb6f4a44bf1513eafbc7c13997cd86c", "spec_sha": "57b863cff56029a0085eaf1b3416b701ed4fa75418d062358b45753e270c9ffa" } ] ### GET - `/api/v1/versions/[GEM NAME]/latest.json` Returns an object containing the latest version of particular gem. $ curl https://rubygems.org/api/v1/versions/rails/latest.json { "version": "4.2.1" } ### GET - `/api/v2/rubygems/[GEM NAME]/versions/[VERSION NUMBER].(json|yaml)` (API v2) Returns a dictionary with versions details for a specific gem version. To return the version for a specific platform (e.g. "ruby", "java", "x86_64-linux"), use the `platform` query parameter. $ curl https://rubygems.org/api/v2/rubygems/coulda/versions/0.7.1.json { "name": "coulda", "downloads": 101713, "version": "0.7.1", "version_created_at": "2011-08-08T21:23:40.254Z", "version_downloads": 9676, "platform": "ruby", "authors": "Evan David Light", "info": "Behaviour Driven Development derived from Cucumber but as an internal DSL with methods for reuse", "licenses": null, "metadata": { "homepage_uri": "http://coulda.tiggerpalace.com" }, "yanked": false, "sha": "777c3a7ed83e44198b0a624976ec99822eb6f4a44bf1513eafbc7c13997cd86c", "spec_sha": "57b863cff56029a0085eaf1b3416b701ed4fa75418d062358b45753e270c9ffa", "project_uri": "https://rubygems.org/gems/coulda", "gem_uri": "https://rubygems.org/gems/coulda-0.7.1.gem", "homepage_uri": "http://coulda.tiggerpalace.com", "wiki_uri": null, "documentation_uri": null, "mailing_list_uri": null, "source_code_uri": null, "bug_tracker_uri": null, "changelog_uri": null, "funding_uri": null, "dependencies": { "development": [], "runtime": [ { "name": "yourdsl", "requirements": "~> 0.7" } ] }, "built_at": "2011-08-08T04:00:00.000Z", "created_at": "2011-08-08T21:23:40.254Z", "description": "Behaviour Driven Development derived from Cucumber but as an internal DSL with methods for reuse", "downloads_count": 9676, "number": "0.7.1", "summary": "Test::Unit-based acceptance testing DSL", "rubygems_version": ">= 0", "ruby_version": null, "prerelease": false, "requirements": null } ### GET - `/api/v2/rubygems/[GEM NAME]/versions/[VERSION NUMBER]/contents.(json|yaml|sha256)` (API v2) Returns the checksum of every file packaged in a specific gem version. The `platform` query parameter selects a non-default platform, as above. Only versions pushed after RubyGems.org started recording file manifests have this data. Older versions respond `404` with "Content is unavailable for this version." $ curl https://rubygems.org/api/v2/rubygems/rails/versions/8.1.3.1/contents.json { "MIT-LICENSE": { "sha256": "717ba1949502290f8e47688ae2e323acd06c8ca47aec9f7596b15f678c1af4a2" }, "README.md": { "sha256": "293a6407fb786e32297e2ac50f216affe95779ab182fc64ec764dece160a4f80" } } The `sha256` format returns the same data as a shasum file instead: $ curl https://rubygems.org/api/v2/rubygems/rails/versions/8.1.3.1/contents.sha256 717ba1949502290f8e47688ae2e323acd06c8ca47aec9f7596b15f678c1af4a2 MIT-LICENSE 293a6407fb786e32297e2ac50f216affe95779ab182fc64ec764dece160a4f80 README.md ### GET - `/api/v1/attestations/[GEM NAME]-[VERSION].json` Returns the [sigstore](/trusted-publishing) attestations published with a gem version, as an array of sigstore bundles. Versions pushed without attestations return an empty array. $ curl https://rubygems.org/api/v1/attestations/rails-8.1.3.1.json [ { "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", "messageSignature": { ... }, "verificationMaterial": { ... } } ] ### GET - `/api/v1/timeframe_versions.json` Returns an array of gem versions that were created within the timeframe specified by the timestamp parameters. An iso8601 timestamp parameter named `from` is required. This is the time from which you'd like to start querying. You may include an iso8601 timestamp parameter named `to`. If present, only the versions created within `from` and `to` will be returned. If `to` is not given, all versions created between `from` and the current time will be returned. NOTE: The timeframe you specify with `from` and `to` cannot exceed a 7 day span. The results are paginated so the API call will return only the first 30 versions in your timeframe. To get subsequent results, use the page query parameter until an empty response is received. Example response: $ curl 'https://rubygems.org/api/v1/timeframe_versions.json?from=2019-01-18T21:24:29Z&to=2019-01-18T21:24:31Z [{ "name": "rails", "downloads": 158094751, "version": "6.0.0.beta1", "version_downloads": 677, "platform": "ruby", "authors": "David Heinemeier Hansson", "info": "Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.", "licenses": ["MIT"], "metadata": {}, "sha": "f70cc2e606eafd6c3fd1d7e15f015d6a3e5626d34724ba5c0114922a8eb864b8", "project_uri": "http://localhost/gems/rails", "gem_uri": "http://localhost/gems/rails-6.0.0.beta1.gem", "homepage_uri": "http://rubyonrails.org", "wiki_uri": "", "documentation_uri": "http://api.rubyonrails.org", "mailing_list_uri": "http://groups.google.com/group/rubyonrails-talk", "source_code_uri": "http://github.com/rails/rails", "bug_tracker_uri": "http://github.com/rails/rails/issues", "changelog_uri": null, "dependencies": { "development": [], "runtime": [{ "name": "actioncable", "requirements": "= 6.0.0.beta1" }, { "name": "actionmailbox", "requirements": "= 6.0.0.beta1" }, { "name": "actionmailer", "requirements": "= 6.0.0.beta1" }, { "name": "actionpack", "requirements": "= 6.0.0.beta1" }, { "name": "actiontext", "requirements": "= 6.0.0.beta1" }, { "name": "actionview", "requirements": "= 6.0.0.beta1" }, { "name": "activejob", "requirements": "= 6.0.0.beta1" }, { "name": "activemodel", "requirements": "= 6.0.0.beta1" }, { "name": "activerecord", "requirements": "= 6.0.0.beta1" }, { "name": "activestorage", "requirements": "= 6.0.0.beta1" }, { "name": "activesupport", "requirements": "= 6.0.0.beta1" }, { "name": "bundler", "requirements": "\u003e= 1.3.0" }, { "name": "railties", "requirements": "= 6.0.0.beta1" }, { "name": "sprockets-rails", "requirements": "\u003e= 2.0.0" }] }, "built_at": "2019-01-18T00:00:00.000Z", "created_at": "2019-01-18T21:24:30.197Z", "description": "Ruby on Rails is a full-stack web framework optimized for programmer happiness and sustainable productivity. It encourages beautiful code by favoring convention over configuration.", "downloads_count": 677, "number": "6.0.0.beta1", "summary": "Full-stack web application framework.", "rubygems_version": "\u003e= 1.8.11", "ruby_version": "\u003e= 2.5.0", "prerelease": true, "requirements": [] }] Gem Download Methods -------------------- ### GET - `/api/v1/downloads.(json|yaml)` Returns an object containing the total number of downloads on RubyGems. $ curl https://rubygems.org/api/v1/downloads.json { "total": 461672727 } ### GET - `/api/v1/downloads/[GEM NAME]-[GEM VERSION].(json|yaml)` Returns an object containing the total number of downloads for a particular gem as well as the total number of downloads for the specified version. $ curl https://rubygems.org/api/v1/downloads/rails_admin-0.0.0.json { "version_downloads": 3142, "total_downloads": 3142 } ### GET - `/api/v1/downloads/all.(json|yaml)` Returns the 50 most downloaded gem versions, each as a pair of the version record and its download count. $ curl https://rubygems.org/api/v1/downloads/all.json { "gems": [ [{ "number": "1.6.2", "full_name": "jmespath-1.6.2", ... }, 648386198], ... ] } Owner Methods ------------- ### GET - `/api/v1/owners/[USER HANDLE|USER ID]/gems.(json|yaml)` View all gems for a user. This is all the gems a user can push to. Owner gems list can be requested with both user handle or user id. $ curl https://rubygems.org/api/v1/owners/qrush/gems.json [ { "name": "factory_bot", ... }, ... ] ### GET - `/api/v1/gems/[GEM NAME]/owners.(json|yaml)` View all owners of a gem. These users can all push to this gem. `role` is either `owner` or `maintainer`. `email` appears only for users who have made their email address public. $ curl https://rubygems.org/api/v1/gems/gemcutter/owners.json [ { "id": 1, "handle": "qrush", "email": "nick@quaran.to", "role": "owner" }, { "id": 7644, "handle": "gemcutter", "role": "owner" } ] ### POST - `/api/v1/gems/[GEM NAME]/owners` Add an owner to a RubyGem you own, giving that user permission to manage it. See [Owner & Maintainer Roles](/managing-owners-using-ui#owner--maintainer-roles) for more details on roles. The new owner is added unconfirmed. Ownership access begins once they click the confirmation link mailed to them. $ curl -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -F 'email=josh@technicalpickles.com&role=owner' \ https://rubygems.org/api/v1/gems/gemcutter/owners techpickles was added as an unconfirmed owner. Ownership access will be enabled after the user clicks on the confirmation mail sent to their email. ### DELETE - `/api/v1/gems/[GEM NAME]/owners` Remove a user's permission to manage a RubyGem you own. $ curl -X DELETE -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -d "email=josh@technicalpickles.com" \ https://rubygems.org/api/v1/gems/gemcutter/owners Owner removed successfully. ### PATCH - `/api/v1/gems/[GEM NAME]/owners` Update an existing owner's role for a RubyGem you own. See [Owner & Maintainer Roles](/managing-owners-using-ui/#owner--maintainer-roles) for more details on roles. $ curl -X PATCH -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -d "email=josh@technicalpickles.com&role=maintainer" \ https://rubygems.org/api/v1/gems/gemcutter/owners Owner updated successfully. Profile Methods ------------- ### GET - `/api/v1/profiles/[USER HANDLE|USER ID].(json|yaml)` View basic user info for a user. `email` appears only if the user has made their email address public. $ curl https://rubygems.org/api/v1/profiles/qrush { "id": 1, "handle": "qrush", "email": "nick@quaran.to" } The same user can be requested by id: $ curl https://rubygems.org/api/v1/profiles/1 ### GET - `/api/v1/profile/me.(json|yaml)` View basic user information for your account, including Multi-factor authentication status. Requires username and password to be passed. `mfa` is one of `disabled`, `ui_only`, `ui_and_api` or `ui_and_gem_signin`. A `warning` key is present when the account's MFA level is below the recommended one. $ curl -u "nick@gemcutter.org:schwwwwing" \ https://rubygems.org/api/v1/profile/me { "id": 1, "handle": "qrush", "email": "nick@quaran.to", "mfa": "ui_and_api" } WebHook Methods --------------- ### GET - `/api/v1/web_hooks.(json|yaml)` List the webhooks registered under your account. $ curl -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ https://rubygems.org/api/v1/web_hooks.json { "all gems": [ { "url": "http://gemwhisperer.heroku.com", "failure_count": 1 } ], "rails": [ { "url": "http://example.com", "failure_count": 0 } ] } ### POST - `/api/v1/web_hooks` Create a webhook. Requires two parameters: `gem_name` and `url`. Specify `*` for the `gem_name` parameter to apply the hook globally to all gems. $ curl -X POST -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -F 'gem_name=rails' -F 'url=http://example.com' \ https://rubygems.org/api/v1/web_hooks Successfully created webhook for rails to http://example.com $ curl -X POST -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -F 'gem_name=*' -F 'url=http://example.com' \ https://rubygems.org/api/v1/web_hooks Successfully created webhook for all gems to http://example.com ### DELETE - `/api/v1/web_hooks/remove` Remove a webhook. Requires two parameters: `gem_name` and `url`. Specify `*` for the `gem_name` parameter to apply the hook globally to all gems. $ curl -X DELETE -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -d 'gem_name=rails' -d 'url=http://example.com' \ https://rubygems.org/api/v1/web_hooks/remove Successfully removed webhook for rails to http://example.com $ curl -X DELETE -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -d 'gem_name=*' -d 'url=http://example.com' \ https://rubygems.org/api/v1/web_hooks/remove Successfully removed webhook for all gems to http://example.com ### POST - `/api/v1/web_hooks/fire` Test fire a webhook. This can be used to test out an endpoint at any time, for example when you're developing your application. Requires two parameters: `gem_name` and `url`. Specify `*` for the gem_name parameter to apply the hook globally to all gems. An `Authorization` header is included with every fired webhook so you can be sure the request came from RubyGems.org. The value of the header is the SHA2-hashed concatenation of the gem name, the gem version and your API key. $ curl -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -F 'gem_name=rails' -F 'url=http://example.com' \ https://rubygems.org/api/v1/web_hooks/fire Successfully deployed webhook for rails to http://example.com $ curl -H 'Authorization:rubygems_b9ce70c306b3a2e248679fbbbd66722d408d3c8c4f00566c' \ -F 'gem_name=*' -F 'url=http://example.com' \ https://rubygems.org/api/v1/web_hooks/fire Successfully deployed webhook for all gems to http://example.com Activity Methods ------------ ### GET - `/api/v1/activity/latest` Pulls the 50 gems most recently added to RubyGems.org (for the first time). Returns an array of the JSON or YAML representation of the gems. $ curl 'https://rubygems.org/api/v1/activity/latest.json' ### GET - `/api/v1/activity/just_updated` Pulls the 50 most recently updated gems. Returns an array of the JSON or YAML representation of the gem versions. $ curl 'https://rubygems.org/api/v1/activity/just_updated.json' Misc Methods ------------ ### POST - `/api/v1/api_key.(json|yaml)` Create a new API key using HTTP basic auth, and return it. Keys are stored hashed, so this response is the only chance to read the key. Accepts `name`, the scopes to enable (see [API key scopes](/api-key-scopes)), and optionally `expires_at`, `rubygem_name` to scope the key to a single gem, and `mfa` to require an OTP when the key is used. $ curl -X POST -u "nick@gemcutter.org:schwwwwing" \ -d 'name=ci-push' -d 'push_rubygem=true' \ https://rubygems.org/api/v1/api_key.json { "rubygems_api_key": "rubygems_701243f217cdf23b1370c7b66b65ca97", "status": "ok" } ### PATCH - `/api/v1/api_key` Update the scopes of an existing key, passed as the `api_key` parameter. $ curl -X PATCH -u "nick@gemcutter.org:schwwwwing" \ -d 'api_key=rubygems_701243f217cdf23b1370c7b66b65ca97' \ -d 'yank_rubygem=true' \ https://rubygems.org/api/v1/api_key Scopes for the API key ci-push updated > NOTE: `GET /api/v1/api_key`, which `gem signin` used to call, has been retired > and now responds `410 Gone`. Create keys with the request above or on the > [API keys page](https://rubygems.org/profile/api_keys). ### POST - `/api/v1/oidc/trusted_publisher/exchange_token` Exchange an OIDC ID token for a RubyGems API key. This endpoint is intended to be used by the [`release-gem`](https://github.com/rubygems/release-gem) GitHub Action for [trusted publishing](/trusted-publishing#releasing-gems-with-a-trusted-publisher). The request body must be a JSON object with a single key, `jwt`, whose value is the ID token (as a string). $ curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" \ -d '{"jwt": $ID_TOKEN}' \ https://rubygems.org/api/v1/oidc/trusted_publisher/exchange_token" { "rubygems_api_key": "rubygems_701243f217cdf23b1370c7b66b65ca97", "name": "GitHub Actions rubygems/configure-rubygems-credentials @ .github/workflows/token.yml", "scopes": ["push_rubygem"], "expires_at": "2021-01-01T00:00:00Z" } --- # RubyGems.org Compact Index API Source: https://guides.rubygems.org/rubygems-org-compact-index-api/ Details of the Compact Index API used for Bundler dependency resolution Compact Index API ----------------- The Compact Index API is considered a stable public API. The primary index file is the `versions` file, which provides the name, versions and the MD5 checksum of each rubygem `info` file. If you need to collect all info about all rubygems, please use the [public data dumps](https://rubygems.org/pages/data) of the rubygems.org database. ### Fetching and Caching Example Response (with some headers ignored): $ curl -I https://rubygems.org/info/bundler HTTP/2 200 last-modified: Fri, 22 Mar 2024 13:09:59 GMT etag: "40148273a7c7cd16b49d00a9935fd445" cache-control: max-age=60, public content-type: text/plain; charset=utf-8 repr-digest: sha-256="pf7Ts7NTRac//JxO9ke3IYbcWx8kcVn9N0mbm5EJpP0=" accept-ranges: bytes All compact index endpoints support ETags with the `If-None-Match` header. If-None-Match: "40148273a7c7cd16b49d00a9935fd445" The compact index is designed to be fetched using the HTTP `Range` header. When a previously fetched copy is present, a ranged request to take advantage of the appended line pattern. Range: bytes=#{range_start}- Responses from the `/versions` and `/info/[GEM]` endpoints will include the `Repr-Digest` header. The digests will have at least the SHA256 checksum of the entire file whether the response includes the full file or a partial response. *Please note that a `Digest` header is present, but it is deprecated and may be removed without notice.* When the Range header is satisfied, append the contents at exactly the starting byte, then compute the SHA256 checksum of the resulting file. If the result matches the `Repr-Digest` header's SHA256 checksum, the file is considered complete and up-to-date. Each line in the `/versions` file includes the latest MD5 calculation of the matching `/info` file for that rubygem at the time the line was written. The latest MD5, closest to the end of the file, will match the MD5 of the up-to-date `/info` file. Exact implementation details are available in the [Bundler CompactIndexClient::Updater](https://github.com/ruby/rubygems/blob/master/lib/bundler/compact_index_client/updater.rb). ### GET - `/versions` Returns a custom text based format containing information about all versions of all rubygems. This API endpoint is intended to be a compact index of all possible rubygem versions. When new rubygems or rubygems versions are added or when a rubygem is yanked, it is added to the end of the file using the format detailed below. The file is append only during the month which improves caching performance. It is recalculated at the start of each month, removing yanked rubygems and compressing new versions into one line for each rubygem. *Warning: this is a big file. Example is truncated.* $ curl https://rubygems.org/versions created_at: 2024-04-01T00:00:05Z --- - 1 05d0116933ba44b0b5d0ee19bfd35ccc -A 0.0.0 8b1527991f0022e46140907a7fc4cfd4 .cat 0.0.1 631fd60a806eaf5026c86fff3155c289 .omghi 1,2 7a67c0434100c2ab635b9f4865ee86bd 0mq 0.1.0,0.1.1,0.1.2,0.2.0,0.2.1,0.3.0,0.4.0,0.4.1,0.5.0,0.5.1,0.5.2,0.5.3 6146193f8f7e944156b0b42ec37bad3e [...SNIP...] active_model_serializers -0.9.10 7ad37af4aec8cc089e409e1fdec86f3d active_model_serializers 0.9.11 a6d40e97b289ee6c806e5e9f7031623b openapi_first 1.4.1 40fbfdebcbfee3863df697e1d641f637 #### `versions` File Format The format of the `versions` file uses one line per rubygem at computation time, with additional lines appended to the end that may include new or yanked versions of a rubygem already present earlier in the file. The lines preceeding `---` should be considered opaque metadata. created_at: 2024-04-01T00:00:05Z --- Each following line gives information about 1 rubygem with the format: RUBYGEM [-]VERSION_PLATFORM[,VERSION_PLATFORM],...] MD5 The parts of this line are as follows: 1. **`RUBYGEM`** - The name of the rubygem. 2. **`(SPACE)`** - The space character. 3. **`[(MINUS)]`** - (optional) The `-` (minus) character. Only present if the version following it has been yanked since the `versions` file was last recalculated. 4. **`VERSION_PLATFORM`** - A rubygem VERSION wich may include the PLATFORM. This combined format is described in more detail in the `info` file format section. 5. **`[(COMMA)VERSION]`** - (optional) A `,` (comma) character, indicating that another VERSION will follow. Read comma delimited VERSION chunks until a space is encountered. 6. **`(SPACE)`** - The space character. 7. **`MD5`** - The MD5 of the rubygem "info" file, described below. Only the *last* MD5 for a gem name in the `versions` file should be considered accurate for the related info file. For more detail, see [the parser in Bundler](https://github.com/rubygems/rubygems/blob/master/lib/rubygems/resolver/api_set/gem_parser.rb). ### GET - `/info/