Build a Ruby Gem
Table of Contents
:ID: E7593CFF-18DA-4385-A78C-C879ADDA7E3B
# What is this?
A reference for building a Ruby gem. See also the official RubyGem.org Instructions for the latest info on this. There’s probably a bunch of stuff here that is outdated.
There’s a cool 8min
synopsis of most of this https://www.youtube.com/watch?v=g2zJC2XKblo
# Naming Conventions
- Lowercase
- Underscores to separate words
- Dash to indicate an extension of an existing gem
# Scaffold the Gem
bundle gem {{ GEM_NAME }}
- Answer prompts about which testing suite to use, CI, license, code of conduct, changelog, etc.
- In the root dir
# The .gemspec file
# Configuration
# Global Configuration
- Create a configuration
attr_accessor
on the main module def self.configure(configuration_class)
class method takes a block and instantiates aConfiguration
object. See this example.
# Local Configuration
This things is instantiated with a config object.
# Middleware configuration
See sidekiq example.
# Versioning
- Version numbers by default are in
lib/my-gem/version.rb
file. Why is there a file for this and not just hardcoded in the gemspec. No idea. - See semantic versioning.
- See also https://bundler.io/guides/gemfile.html
# Extending Rails with Railties
Rails::Railtie
provides several hooks to extend Rails and/or modify the initialization process.- To implement, an initializer is given an arbitrary name and the related code is placed within the ensuing block.
Use an initializer to load a module into a Rails component.
require 'rails' require 'my_gem/some_class' module my_gem class Railtie < Rails::Railtie initializer "my_railtie.configure_rails_initialization" do ActionView::Base.send(:include, MyGem::Stuff) end end end
# ActiveSupport on_load
See also will_paginate example.
require 'rails' require 'my_gem/some_class' class Railtie < Rails::Railtie initializer "my_railtie.configure_rails_initialization" do ActiveSupport.on_load(:action_view) do include MyGem::SomeClass end end end # lib/my_gem require "my_gem/railtie" if defined?(Rails)
An alternative, and possibly safer approach is to just manually include the gem’s module in the Rails’ class where you want to use it.
# Running the Gem Locally
bin/console
bundle console
irb -r my_gem -I ./lib
or add rake task for the lazytask :console do exec "irb -r mega_lotto -I ./lib" end
-e
flag runs a line of code when the environment starts. Useful if you need to run a config block.- Add it to a Gemfile by pointing to local checkout path
gem "my_gem", path: "~/development/ruby/gems/locotimezone"
# Testing
The Rakefile should already be setup to gather test files and run them using the test framework selected with
bundle gem
.require 'bundler/gem_tasks' require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) do |task| task.rspec_opts = ['—color'] end task default: :spec
# Gem Dependencies
Do not add gems to the Gemfile, just define the dependencies in the .gemspec
- Optimistic Version Constraint
Specify any version above a certain version gem
'some_dependency, '>= 1.0'
- Exact Version
gem 'rails', '4.0.2'
- Pessimistic Version Constraint
- Keep the version between minor releases. Example below will
install most recent version between 4.0.0 and 4.1.0. gem
'sass-rails', '~> 4.0.0'
- The decimal places change the version range. This example will
accept patches and minor releases: (4.1, 4.2, 4.0.1,…) gem
'sass-rails', '~> 4.0'
- Keep the version between minor releases. Example below will
install most recent version between 4.0.0 and 4.1.0. gem
# Loading Support Libraries
- An optional support library can be loaded in the Gemfile when adding
the gem:
gem ‘locotimezone' require: ‘locotimezone/web'
. - Or use an initializer in Rails to add the require statement.
- Since a support library is optional, don’t require it in the main file of my_gem.rb
# Adding an Executable to bin/
In addition to providing libraries of Ruby code, gems can also expose one or many executable files to your shell’s PATH.* 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.* touch bin/my_executable* the name of the file is how it will be called in the terminal* chmod a+x bin/my_executable* include the executable and dir in the gemspec
# !/usr/bin/env ruby require_relative "../lib/locotimezone"
rake install
to test it. If using rbenv, might need to rehash before it becomes available- Use the Ruby OptionParser to give the script the ability to use switches. See resque cmd line example
# Building
gem build my_gem.gemspec
# Install
gem install my_gem
- It will look locally first for a gem of that name, before going to rubygems.org
- Rake install in the gem project root will build and install it.
# Push
# Setup to Push to rubygems.org
curl -u {{ USERNAME }} https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
# Push to Rubygems.org
gem push my_gem.gem
Build and push in one command with rake release
# Misc
# Copy an installed Gem’s source code to CWD
$ gem unpack some-gem