A Guide to Ruby Gem Post-Install Messages

As gem authors, one of the ways we can provide important information to users of our gems is through post-install messages. Let’s explore what they are, how to set them up, what to include and when to use them.

What are Post-Install Messages?

As Rubyists, we have plenty experiences installing gems. By running gem install rails, we’re asking Rubygems to install the gem named rails on to our system.

The typical output of installing a gem with no other dependencies (assuming it completes successfully) is minimal:

$ gem install so_meta
Successfully installed so_meta-0.1
1 gem installed

As you can see, we ran gem install so_meta and the output confirmed the install, with nothing more.

If you’ve used the HTTParty gem, you’ve probably seen the additional line of output it generates when you run gem install httparty:

$ gem install httparty
When you HTTParty, you must party hard!
Successfully installed httparty-0.13.7
1 gem installed

Where did When you HTTParty, you must party hard! come from? It turns out the source of that text was a [post-install message defined in the gemspec.

Now, I know what you’re probably thinking…what good is that message? That’s up for debate. In fact, that specific message in HTTParty has been the source of much debate over the years.

How to configure a Post-Install Message

As we’ve seen before, the gemspec file (located at the root of the gem) defines the specification of a Ruby gem. Using bundler to bootstrap a new gem will automatically create this file. Here’s an example of a default gemspec file created by bundler using the command bundle gem brandon (brandon being the name of my fake gem):

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'brandon/version'

Gem::Specification.new do |spec|
  spec.name          = "brandon"
  spec.version       = Brandon::VERSION
  spec.authors       = ["Brandon Hilkert"]
  spec.email         = ["brandonhilkert@gmail.com"]

  spec.summary       = %q{TODO: Write a short summary, because Rubygems requires one.}
  spec.description   = %q{TODO: Write a longer description or delete this line.}
  spec.homepage      = "TODO: Put your gem's website or public repo URL here."

  # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
  # delete this section to allow pushing this gem to any host.
  if spec.respond_to?(:metadata)
    spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
  else
    raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
  end

  spec.files         = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
  spec.bindir        = "exe"
  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib"]

  spec.add_development_dependency "bundler", "~> 1.11"
  spec.add_development_dependency "rake", "~> 10.0"
  spec.add_development_dependency "minitest", "~> 5.0"
end

Aside from summary, description, and homepage, we can leave the rest of this file intact. These setter attributes on the Gem::Specification.new instance allow us to define the options and metadata necessary to properly configure and release a Ruby gem (see the Rubygems specification reference for an extensive list of options).

As you might have guessed by now, a post-install message is an option available in the gemspec. The value can be a simple string or a more complex heredoc.

The simplest example being:

spec.post_install_message = "My test post-install message."

With that in our gemspec, now when we install our fake gem brandon, we’ll see the following output:

$ gem install brandon
My test post-install message.
Successfully installed brandon-0.1.0
1 gem installed

Easy, huh?

If we wanted to include a more complex message with line breaks and other formatting, another option would be something like:

s.post_install_message = %q{
My test post-install message.

Another post-install message a few lines down.
}

The formatting of these messages can get weird because whitespace is preserved in multiline strings. If you’re looking to include anything more complex than a simple string literal, it’s worth experimenting by installing locally and confirming it’s what you want.

The NewRelic gem is another example that comes to mind that commonly includes more than just a simple string. Looking back at an older version of the NewRelic gem yields the following post_install_message:

s.post_install_message = %q{
Please see http://support.newrelic.com/faqs/docs/ruby-agent-release-notes
for a complete description of the features and enhancements available
in version 2.12 of the Ruby Agent.

For details on this specific release, refer to the CHANGELOG file.

}

Notice the message includes a line break both before and after the message. This will help isolate from our post-install messages when included in the longer output of a command like bundle install. Again, if you’re focused on formatting and getting it right, it’s worth installing locally in to something like a Rails application which yields more output than using gem install [gemname].

When to Use Post-Install Messages

The examples above use post-install messages for different reasons. HTTParty’s message wasn’t for a serious technical or information reason, just a light-hearted message that’s garnered quite a bit of negative attention from users that don’t appreciate it.

My suggestion would be to avoid any non-sensical messages and only provide a post-install message for something like breaking changes or information you think is critical to the usage of your gem. In most cases, post-install messages are most useful when a user is upgrading from an older version of your gem and the new version includes backwards-incompatible changes. Whether is be syntactical changes or core functionality, post-install messages provide us as gem authors a means to keep our users updated.

What to Include in Post-Install Messages

If you’re adhering to semantic versioning and introduce any breaking changes in a major release, a post-install message is a great way to warn users about the changes. However, one thing you want to avoid is enumerating your gem’s full changelog in the message. In most cases, a short notice about the backwards incompatible changes and a URL for more information is enough.

I introduced a new public API in Sucker Punch, which warranted a major release. Because of these backwards-incompatible changes, I added a post-install message to the new version:

$ gem install sucker_punch
Fetching: sucker_punch-2.0.1.gem (100%)
Sucker Punch v2.0 introduces backwards-incompatible changes.
Please see https://github.com/brandonhilkert/sucker_punch/blob/master/CHANGES.md#20 for details.
Successfully installed sucker_punch-2.0.1
1 gem installed

“Sucker Punch v2.0 introduces backwards-incompatible changes” provided the heads up that something was different. The URL in the following line allows the users to see a more extension list of the changes and to make adjustments in their application if necessary.

Summary

In addition to documentation through a README or wiki, post-install messages are a great way to keep users of our gems informed. Having access to the output of their console is a privilege, so use it sparingly. Like the boy who cried wolf, if we include a wall of text with each release of our gem, users will learn to ignore it and that would negatively affect its value for everyone.