skip to content

Gemspec & Publishing

A .gemspec declares files, require_paths, required_ruby_version, runtime and development dependencies and metadata; gem build and gem push ship it to rubygems.org. Asked with yank and MFA.

on this pageshow

explore

questions

6

In RubyGems, what is a .gemspec file, which fields must it set, and what does gem build produce from it?

level: juniorimportance: must knowfreq 52%

answer

  1. Gem::Specification.new block
  2. name, version, summary, authors
  3. errors stop the build, warnings do not
  4. name-version.gem
  5. gem build --strict

basics

~10 s

A .gemspec is Ruby code that builds a Gem::Specification: name, version, summary, authors, files, require_paths and dependencies. gem build validates it and packages the listed files into name-version.gem, the file gem push uploads.

solid answer

~30 s

A `.gemspec` is a Ruby file whose `Gem::Specification.new do |spec| ... end` block describes the gem. RubyGems **requires** `name`, `version` and `summary`, a non-empty `authors`, and at least one entry in `require_paths` (default `["lib"]`); `files` lists what gets packaged. `gem build hue_palette.gemspec` validates the spec: missing required values, a listed path that is not a file, or TODO placeholders are **errors**, while no `license`, no `homepage` or no `required_ruby_version` are **warnings**. On success it prints `Successfully built RubyGem` and writes `hue_palette-1.0.0.gem`. `--strict` turns warnings into errors, and `metadata` adds string links such as `source_code_uri` that rubygems.org shows.

code

ruby · 18 lines
ruby
# hue_palette.gemspec
require_relative "lib/hue_palette/version"   # defines HuePalette::VERSION = "1.0.0"

Gem::Specification.new do |spec|
  spec.name     = "hue_palette"
  spec.version  = HuePalette::VERSION
  spec.authors  = ["Ada Example"]
  spec.summary  = "Build harmonious colour palettes from a base hue"
  spec.homepage = "https://example.com/hue_palette"
  spec.license  = "MIT"
  spec.required_ruby_version = ">= 3.2"

  spec.files         = Dir["lib/**/*.rb", "LICENSE.txt", "README.md"]
  spec.require_paths = ["lib"]

  spec.metadata["source_code_uri"] = "https://example.com/hue_palette/src"
  spec.metadata["changelog_uri"]   = "https://example.com/hue_palette/CHANGELOG.md"
end

go deeper

for a junior

Know that a gemspec is Ruby code building a Gem::Specification, the required fields, and that gem build writes name-version.gem.

for a middle

Explain which problems are build errors versus warnings, how metadata links work, and how to inspect a built .gem before pushing it.

for a senior

Make release builds strict, verify the packaged file list, and keep the gemspec free of side effects so every machine builds the same archive.

for a principal

Set a team standard for gemspec fields and metadata across many gems, and decide which validations release automation must enforce.

## What a gemspec is A **gem** is a packaged Ruby library, and its **specification** says what it is: name, version, authors, which files it contains, which directory to load code from, what it depends on and which Ruby it supports. The `.gemspec` file is plain **Ruby code** that builds a `Gem::Specification` object: - the file usually sits at the root of the project, named after the gem (`hue_palette.gemspec`); - it typically `require_relative`s the gem's `version.rb`, so the version lives in one place (`HuePalette::VERSION`); - because it is Ruby, it can compute values, for example building `files` from `Dir[...]` or from `git ls-files`. ## Required and recommended fields `Gem::Specification` validation distinguishes **errors**, which stop the build, from **warnings**, which only print. | Field | If missing or wrong | |---|---| | `name`, `version`, `summary` | error: `missing value for attribute ...` | | `authors` | error: `authors may not be empty` | | `require_paths` | error if empty; default is `["lib"]` | | `files` | warning `no files specified`; an entry that is not a file is an error | | `license` / `licenses` | warning recommending an SPDX identifier | | `homepage` | warning `no homepage specified`; must be an HTTP(S) URI if set | | `required_ruby_version` | warning asking you to state the oldest supported Ruby | Other checks worth knowing: - An author, email, summary or description that still starts with a `TODO` or `FIXME` placeholder is an **error**, which catches half-edited generated gemspecs. - A `description` identical to the `summary` is a warning. - The gem must not list its own `.gem` file in `files`. ## metadata `spec.metadata` is a Hash of **string keys to string values** (keys up to 128 bytes, values up to 1024). RubyGems recognises link keys such as `homepage_uri`, `source_code_uri`, `changelog_uri`, `documentation_uri`, `bug_tracker_uri`, `wiki_uri`, `mailing_list_uri`, `download_uri` and `funding_uri`; each must be a valid `http(s)` URL, and rubygems.org shows them on the gem's page. Other keys, such as `allowed_push_host` and `rubygems_mfa_required`, control publishing. ## What gem build does `gem build hue_palette.gemspec` (or plain `gem build` when exactly one gemspec is in the current directory): 1. loads the gemspec, which runs its Ruby code; 2. validates it, printing warnings and stopping on errors; 3. writes a `.gem` archive holding the files from `files` plus the serialised specification; 4. prints `Successfully built RubyGem`, the name, the version and the file name, `hue_palette-1.0.0.gem`. Useful options: - `--strict` treats every warning as an error (`specification has warnings`), a good setting for release automation. - `--force` skips validation entirely, which is rarely a good idea. - `-o, --output FILE` chooses the output file name. RubyGems 4.0 removed the old `-C` option of `gem build`; change into the directory first instead. ## Common gemspec mistakes - **Leaving generated placeholders.** A summary or author that still begins with `TODO` fails the build; a description identical to the summary only warns. - **A files list that matches nothing.** `Dir["lib/**/*.rb"]` in a gem whose code lives elsewhere produces an almost empty gem, with at most a `no files specified` warning. - **Loading the gem's own code.** `require "hue_palette"` inside the gemspec runs library code (and its dependencies) at build time; `require_relative` of just the version file avoids that. - **Side effects.** Shelling out to tools the build machine may lack, or reading environment variables, makes builds differ between machines. - **Symbols in metadata.** `spec.metadata[:source_code_uri] = ...` fails validation, because keys must be Strings. ## Checking the result before publishing - `gem spec hue_palette-1.0.0.gem` prints the specification stored inside the archive. - `gem unpack hue_palette-1.0.0.gem` extracts it so you can see exactly which files shipped. - `gem install ./hue_palette-1.0.0.gem` installs the local file for a smoke test. Only after that does `gem push hue_palette-1.0.0.gem` upload it to rubygems.org.

  • Why is a .gemspec written in Ruby rather than as a static data file?
    Because values are often computed: the version comes from `require_relative "lib/.../version"`, and `files` is built from `Dir[...]` or `git ls-files`. The flip side is that the gemspec runs as code whenever it is loaded, so it should stay free of side effects and must not depend on anything the build machine lacks.
  • What does gem build --strict change?
    Normally warnings, such as a missing license, homepage or `required_ruby_version`, are printed and the build still succeeds. With `--strict`, any warning fails the build with `specification has warnings`, which suits release automation that should never publish a gem with an incomplete spec.

saying these in an interview costs you the question

  • Thinks a gemspec is YAML or JSON rather than Ruby code
  • Believes license and homepage are required by gem build
  • Assumes gem build packages every file in the project directory
  • Treats metadata values as any Ruby object rather than strings
  • Still uses gem build -C, removed in RubyGems 4.0
open as a page

In a RubyGems gemspec, what is the difference between add_dependency and add_development_dependency, and what goes wrong if you mix them up?

level: middleimportance: must knowfreq 55%

basics

~20 s

add_dependency declares a runtime dependency, installed and activated with your gem. add_development_dependency declares a tool needed only to work on the gem; gem install skips it unless --development is given, and it is never activated.

open as a page

When you publish version 1.0 of a gem with gem push, how do RubyGems API keys, MFA and --otp work, and which gemspec metadata hardens the release?

level: seniorimportance: must knowfreq 42%

basics

~20 s

gem push uploads a built .gem using an API key from gem signin or GEM_HOST_API_KEY. With MFA enabled, the server demands a one-time code passed via --otp or GEM_HOST_OTP_CODE. Metadata rubygems_mfa_required and allowed_push_host harden pushes.

open as a page

In a RubyGems gemspec, what do files, require_paths and required_ruby_version control, and why can a freshly published gem fail with LoadError?

level: middleimportance: should knowfreq 40%

basics

~20 s

files lists exactly what goes into the .gem, require_paths names the directories added to the load path on activation (default lib), and required_ruby_version filters installs. A file missing from files, or code outside require_paths, raises LoadError after install.

open as a page

In RubyGems, what makes a version such as 1.0.0.rc1 a prerelease, and how do users install one before the final 1.0.0?

level: middleimportance: should knowfreq 28%

basics

~10 s

A RubyGems version containing a letter, such as 1.0.0.rc1 or 1.0.0.beta.2, is a prerelease and sorts below 1.0.0. gem install ignores prereleases unless given --prerelease or a -v requirement naming one.

open as a page

You pushed hue_palette 1.0.0 to rubygems.org and it contains an API token by mistake. What does gem yank do, what does it not undo, and what do you do next?

level: seniorimportance: should knowfreq 32%

basics

~20 s

gem yank hue_palette -v 1.0.0 removes that version from the rubygems.org index so new installs cannot resolve it. It cannot recall copies already downloaded, so revoke the leaked token first, yank, and ship a fixed 1.0.1.

open as a page