17.2. Installation and Packaging
Your end user's "out-of-the-box experience" should be as painless as possible. As users, we agree fervently with this; as developers, we'd sometimes prefer not to be bothered with packaging and installation issues.
Fortunately, these matters are less painful than in some other languages and environments. The two things you most need to know about are the setup library and RubyGems, Ruby's "native" packaging and deployment system.
The setup.rb library is the work of Minero Aoki (who also created install.rb, used less often now).
Some would say this is becoming obsolete as RubyGems improves. Others would say they have issues with gems (technical, political, or otherwise). Some would say a "good citizen" should include a setup.rb even in a gem (making it easier for people to repackage in other forms, such as a Linux distro-specific packager). We'll leave that for you to decide.
Half the magic of using this library is just putting things in the right places. It requires that you structure your archive in a simple, sensible way (with well-named directories).
Let's assume you are distributing a single package in an archive (the most common case). You would arrange your directories something like this (dropping a copy of setup.rb in at the top level).
top_level/ setup.rb metaconfig (optional) lib/ ext/ myext/ bin/ data/ conf/ man/ test/
Empty directories may be omitted. These directories are used as follows:
In general, files that don't require any processing are simply copied to their proper locations. For customized operations you may want to perform, there are hooks into every aspect of the process.
Typically the three main phases are config, setup, and install, invoked by the user in that order. (The last step may require sudo access or actual root access.)
You create a hook simply by placing a Ruby program with the appropriate name in the appropriate directory. For example, if I want to do something special with lib/foobar before it is processed, I could create a file lib/foobar/pre-setup.rb with arbitrary code in it.
These filenames are formed by either pre or post, followed by a hyphen, followed by a task name. The valid task names are config, setup, install, test, clean, and dist-clean.
The setup.rb library has the concept of a source directory and an object directory. In general, you should read from the source directory and write to the current directory as needed.
There is a "hook API" to make some of these programming tasks easier. Some of the methods in the API are as follows:
The file metaconfig is optional at the top level. If it exists, it will be used to specify certain global configuration options. For this, there is the "metaconfig API," a small set of convenience methods. Some of these are
For more exhaustive coverage of both these APIs, refer to the latest documentation online.
The initial idea and name for RubyGems came from Ryan Leavengood, but the current implementation has its origins in a late-night hackfest after hours at the 2003 International Ruby Conference in Austin, Texas. That original code base was created by Chad Fowler, Jim Weirich, David Alan Black, Rich Kilmer, and Paul Brannan. Since then, several other individuals have contributed to this effort (notably Eric Hodel and Ryan Davis).
At the time of this writing, RubyGems is probably the best most commonly used packaging scheme. However, it has not yet made it into the distribution. With the ironing out of a few more issues, I think that it will be truly standard in Ruby.
As with the rest of this chapter, we're talking here from the developer's perspective. You will learn here how to package your own code as gems, not to manipulate gems from the outside world. That is a later topic.
A natural question is: Why use gems? The following are some of the benefits:
A gem file typically is named with a short, descriptive unique name followed by a hyphen, followed by a standard version number. The version number is in the form "major dot minor dot tiny" that is nearly universal nowadays (obviously, each number may be more than one digit). The use of rational versioning is encouraged; if you're not familiar with that term, use a search engine to find all the details.
To build a gem, start with a logical directory structure (essentially the same as what setup expects). It's good to put a README file at the top level; this should contain such information as author's name and contact information, copyright, license information, known bugs, and so on. If you write this in RDoc format, it can be included as part of the project's HTML documentation.
One critically important step in building a gem is to create a gem specification (or gemspec) file. This is one of those cases where the line between code and data happily blurs. A gemspec is simply executable Ruby code (as shown here):
require 'rubygems' SPEC = Gem::Specification.new do |s| s.name = "Drummer" s.version = "1.0.2" s.author = "H. Thoreau" s.email = "email@example.com" s.homepage = "http://waldenpond.com/Drummer" s.platform = Gem::Platform::RUBY s.summary = "A Ruby app for those who march to a different drummer" s.files = Dir["./*"] + Dir["*/**"] s.test_file = "test/ts_drum.rb" s.has_rdoc = true s.require_path = "lib" s.extra_rdoc_files = ["README", "ChangeLog"] s.add_dependency "KirbyBase", ">=2.5.0" end
Many of these attributes are self-explanatory given the preceding example. There are a few others, mostly less important or less frequently used. Refer to the latest RubyGems documentation online.
Given a gemspec file, you can create a gem in two ways. First, you may simply run the gemspec (after all, it is Ruby code). It will create the gem of the given name in the current directory. Alternatively, you can use the gem build command and pass it the gemspec name. There is no difference in the result.
Now that you've packaged a gem, make it available however you want on the Web or elsewhere. I strongly recommend using RubyForge to manage your project; if your uploaded archive contains a gemspec, your gem will be created automatically. In the next section, we'll look at Rubyforge and the Ruby Application Archive (RAA).