Skip to content

Ruby Gems — Creating, Publishing and Managing Gems with Gem Tools

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Ruby Gems. We cover key concepts, practical examples, and best practices to help you master this topic.

Ruby Gems are self-contained packages of Ruby code shared via RubyGems with tools for creation, building, versioning, and publishing to rubygems.org.

What You'll Learn

  • Gem structure and creation
  • Gem specification files
  • Building and publishing gems
  • Versioning conventions

Why It Matters

Gems enable code reuse across projects. Rails, RSpec, and Devise are gems. DodaZIP creates gems for reusable file processing components.

Real-World Use

Distributing libraries, sharing utilities between projects, creating plugins for frameworks, commercial Ruby products.

flowchart LR
    A["Gems"] --> B["Structure"]
    B --> C["Gemspec"]
    C --> D["Build"]
    D --> E["Publish"]
    A:::current --> B
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b

Gem Structure

my_gem/
  lib/
    my_gem.rb
    my_gem/
      version.rb
  my_gem.gemspec
  Gemfile
  README.md
  LICENSE.txt

Creating a Gem

# my_gem/lib/my_gem.rb
require_relative "my_gem/version"

module MyGem
  class Error < StandardError; end

  def self.hello(name)
    "Hello, #{name}!"
  end
end

# my_gem/lib/my_gem/version.rb
module MyGem
  VERSION = "0.1.0"
end

Gemspec File

# my_gem/my_gem.gemspec
Gem::Specification.new do |spec|
  spec.name          = "my_gem"
  spec.version       = MyGem::VERSION
  spec.authors       = ["Your Name"]
  spec.email         = ["you@example.com"]
  spec.summary       = "A simple gem"
  spec.description   = "A longer description"
  spec.license       = "MIT"
  spec.files         = Dir["lib/**/*"]
  spec.require_paths = ["lib"]
  spec.add_dependency "json"
  spec.add_development_dependency "rspec"
end

Building and Publishing

gem build my_gem.gemspec
# Successfully built RubyGem
# Name: my_gem
# Version: 0.1.0
# File: my_gem-0.1.0.gem

gem push my_gem-0.1.0.gem
# Pushing gem to https://rubygems.org...
# Successfully registered gem: my_gem (0.1.0)

gem install my_gem
# Successfully installed my_gem-0.1.0

Versioning

module MyGem
  VERSION = "1.2.3"
  # Major.Minor.Patch
  # Breaking.NewFeature.Fix
end

Gem with Executable

# my_gem/exe/my_gem
#!/usr/bin/env ruby
require "my_gem"
puts MyGem.hello(ARGV[0] || "world")

# my_gem/my_gem.gemspec
spec.executables = ["my_gem"]

Common Mistakes

1. Missing License

# Always include MIT, Apache, or GPL license
# spec.license = "MIT"

2. Wrong require path

# spec.require_paths = ["lib"]
# Then require 'my_gem' works because lib/ is in load path

3. Not listing all files

spec.files = Dir["lib/**/*", "exe/*"]
# Missing files won't be included in the gem

4. Hardcoding version

# Instead of: VERSION = "0.1.0"
# Use separate version.rb file for consistency

5. Forgetting to update version

Always bump the version before rebuilding. Tools like gem release and bump help.

Practice Questions

1. What files does a gem need? Gemspec, lib/ directory with entry point, and optionally executables, README, and license.

2. How do you specify dependencies? spec.add_dependency for runtime and spec.add_development_dependency for dev.

3. What is the load path convention? The lib/ directory is added to $LOAD_PATH. Require the gem name from lib/.

4. How do version numbers work? Semantic versioning: MAJOR.MINOR.PATCH. Breaking changes bump MAJOR.

Challenge: Create a gem that provides a String#reverse_words method and build it.

Solution
# lib/word_reverser.rb
class String
  def reverse_words
    split.reverse.join(" ")
  end
end

# word_reverser.gemspec
Gem::Specification.new do |spec|
  spec.name = "word_reverser"
  spec.version = "0.1.0"
  spec.authors = ["You"]
  spec.summary = "Reverses word order in strings"
  spec.files = Dir["lib/**/*"]
end

FAQ

{{< faq question="How do I install a gem locally?" >}} gem install my_gem-0.1.0.gem installs from a local file. gem install my_gem installs from rubygems.org. {{< /faq >}}

{{< faq question="What is the difference between gem and bundle?" >}} Gem is the package format. Bundler manages gem dependencies in a project. bundle install uses Gemfile to install gems. {{< /faq >}}

{{< faq question="Can I have private gems?" >}} Yes, use a private gem server (Gemfury, GitHub Packages) or gem "my_gem", path: "../my_gem" for local development. {{< /faq >}}

{{< faq question="What is a gemspec lockfile?" >}} There isn't one. Gemspec specifies minimum versions. Gemfile.lock from Bundler pins exact versions in applications. {{< /faq >}}

{{< faq question="How do I test my gem during development?" >}} Use bundle exec rake spec with RSpec. Run gem install locally first. Use irb -I lib -r my_gem for quick testing. {{< /faq >}}

Try It Yourself

# Create a minimal gem
mkdir hello_gem && cd hello_gem
mkdir -p lib/hello_gem

cat > lib/hello_gem.rb << 'EOF'
module HelloGem
  VERSION = "0.1.0"
  def self.greet(name) = "Hi #{name}!"
end
EOF

cat > hello_gem.gemspec << 'EOF'
Gem::Specification.new do |s|
  s.name = "hello_gem"
  s.version = "0.1.0"
  s.summary = "A friendly gem"
  s.authors = ["You"]
  s.files = Dir["lib/**/*"]
end
EOF

gem build hello_gem.gemspec

Expected output:

Successfully built RubyGem
Name: hello_gem
Version: 0.1.0
File: hello_gem-0.1.0.gem

What's Next

Now that you understand gems, learn Bundler for managing gem dependencies in your projects.

Topic Description Link
Ruby Bundler Dependency management {{< ref "44-bundler" >}}
Ruby Ractors Parallel execution {{< ref "42-ractors" >}}
Ruby Ecosystem Ruby community and tools {{< ref "46-ecosystem" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro