# Creating and Publishing Gems — Ruby

Source: https://www.geekswithgeeks.com/en/ruby/e-gems

> Structure a gem, version it and publish it.

## Packaging Ruby code

A **gem** packages Ruby code with metadata for reuse. `bundle gem price_tools` scaffolds one: a `lib/price_tools.rb` entry file, `lib/price_tools/version.rb`, a **gemspec** describing name, version, authors, summary, licence, files, required Ruby version and dependencies, plus test, README and CI templates. Library code goes under `lib/` in a namespace module matching the gem name, and Ruby loads it with `require "price_tools"`. Follow **Semantic Versioning**: patch versions for fixes, minor for backward-compatible features, major for breaking changes. In a gem's own gemspec, declare **runtime dependencies** with ranges (`spec.add_dependency "bigdecimal", "~> 3.1"`) rather than exact pins, and keep development dependencies in the Gemfile; gems do not commit their `Gemfile.lock` for consumers. Build and release with `gem build` and `gem push`, or `bundle exec rake release`, and protect your RubyGems.org account with multi-factor authentication. Many companies host private gems on a private server or GitHub Packages.

## Anatomy of a gem

lib/ holds the code, the gemspec describes it, and tests and docs travel alongside.

![A package box opened to show a folder tree, a label card and a small test checklist.](assets/figures/ruby/section-7-map.svg) — Figure 7.1 — Files in a Ruby gem.

## Gemspec and library entry point

Namespaced code, a version constant and dependency ranges.

```ruby
# price_tools.gemspec
Gem::Specification.new do |spec|
  spec.name          = "price_tools"
  spec.version       = PriceTools::VERSION
  spec.authors       = ["Platform Team"]
  spec.summary       = "GST and discount calculations"
  spec.license       = "MIT"
  spec.required_ruby_version = ">= 3.2"
  spec.files         = Dir["lib/**/*.rb", "README.md", "LICENSE.txt"]
  spec.add_dependency "bigdecimal", "~> 3.1"
  spec.metadata["rubygems_mfa_required"] = "true"
end

# lib/price_tools/version.rb
module PriceTools
  VERSION = "1.2.0"
end

# lib/price_tools.rb
require "bigdecimal"
require_relative "price_tools/version"

module PriceTools
  module_function

  def with_gst(amount, rate: BigDecimal("0.18"))
    (BigDecimal(amount.to_s) * (1 + rate)).round(2)
  end
end

# usage: require "price_tools"; PriceTools.with_gst("100")   # 118.0 as a BigDecimal
```

## Do not pin exact versions in a gemspec

A gem that requires `rack = 3.0.8` forces every application using it onto that exact version, causing conflicts. Use pessimistic ranges in gemspecs and let applications lock exact versions.

**Quiz:** In Semantic Versioning, which version bump signals a breaking change?

- [x] Major (1.2.3 -> 2.0.0)
- [ ] Patch (1.2.3 -> 1.2.4)
- [ ] Minor (1.2.3 -> 1.3.0)
- [ ] None

*Answer:* Major (1.2.3 -> 2.0.0). Major versions communicate incompatible API changes.
