Alex's Slip-box

These are my org-mode notes in sort of Zettelkasten style

Build a Ruby Gem

# 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 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 a Configuration object. See this example.

# Local Configuration

This things is instantiated with a config object.

# Middleware configuration

# 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.

# 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 lazy
task :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'

# 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