Ruby Gems — Creating, Publishing and Managing Gems with Gem Tools
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