--- book: - chapter: - title: Introduction to RubyGems page: - body: | Question: I\'ve installed RubyGems and I want to install Rails (for example). How do I do that? Answer: gem install rails And then answer Y when asked about installing dependencies. title: Really Quick Start - body: |- A gem is a packaged Ruby application or library. It has a name (e.g. rake) and a version (e.g. 0.4.16). Gems are managed on your computer using the gem command. You can install, remove, and query (amoung other things) gem packages using the gem command. RubyGems is the name of the project that developed the gem packaging system and the gem command. You can get RubyGems from the "RubyForge":http://rubyforge.org/projects/rubygems repository. title: What is a Gem? - body: | This document demonstrates the the use of the most important features of RubyGems in a quick and high-level way. It is designed to be read all the way through to give the reader a feeling for this technology. More detailed information is available in the "gem command reference":http://docs.rubygems.org/read/book/2. title: About This Document - body: |- h3. RubyGems Features * Easy Installation and removal of RubyGems packages and their dependents. * Management and control of local packages * Package dependency management * Query, search and list local and remote packages * Multiple version support for installed packages * Web-based interface to view the documentation for your installed gems * Easy to use interface for building gem packages * Simple server for distributing your own gem packages h3. RubyGems Benefits Using RubyGems, you can: * download and install Ruby libraries easily * not worry about libraries A and B depending on different versions of library C * easily remove libraries you no longer use * have power and control over your Ruby platform! It's the way it _should_ be. title: About RubyGems - title: Using RubyGems page: - body: |- This chapter gives examples of the most common user opertions performed with the gem command. See the "gem Command Reference":http://docs.rubygems.org/read/book/2 manual for details about particular gem commands. Versioning is a pretty basic concept in RubyGems. You might want to glance at the "Specifying Versions":/read/chapter/16 chapter for a better understanding of how versions work with RubyGems. title: Basic Gem Usage - body: | When you run gem query --remote # shortcut: gem q -R you see will a detailed list of all the gems on the remote server. Sample output (heavily abbreviated):
        *** REMOTE GEMS ***
        
        activerecord (0.8.4, 0.8.3, 0.8.2, 0.8.1, 0.8.0, 0.7.6, 0.7.5)
            Implements the ActiveRecord pattern for ORM.
        
        BlueCloth (0.0.4, 0.0.3, 0.0.2)
            BlueCloth is a Ruby implementation of Markdown, a
            text-to-HTML conversion tool for web writers.
            Markdown allows you to write using an easy-to-read,
            easy-to-write plain text format, then convert it to
            structurally valid XHTML (or HTML).
        
        captcha (0.1.2)
            Ruby/CAPTCHA is an implementation of the 'Completely
            Automated Public Turing Test to Tell Computers
            and Humans Apart'.
        
        cardinal (0.0.4)
            Ruby to Parrot compiler.
        
        cgikit (1.1.0)
            CGIKit is a componented-oriented web application
            framework like Apple Computers WebObjects.  This
            framework services Model-View-Controller architecture
            programming by components based on a HTML file, a
            definition file and a Ruby source.
        
        progressbar (0.0.3)
            Ruby/ProgressBar is a text progress bar library for
            Ruby.  It can indicate progress with percentage, a
            progress bar, and estimated remaining time.
        
        rake (0.4.0, 0.3.2)
            Ruby based make-like utility.
        
The _progressbar_ gem is a nice and simple utility that we will use to demonstrate further features. title: Listing remotely installable gems - body: |- When you run
  gem query --remote --name-matches doom
          # shortcut: gem q -R -n doom
you will see a detailed list of _matching_ gems on the remote server. Sample output:
        *** REMOTE GEMS ***
        
        ruby-doom (0.8, 0.0.7)
            Ruby-DOOM provides a scripting API for creating DOOM
            maps. It also provides higher-level APIs to make map
            creation easier.
        

When you run

  gem query --remote --name-matches doom
          # shortcut: gem q -R -n doom

you will see a detailed list of matching gems on the remote server.

Sample output:

        *** REMOTE GEMS ***
        
        ruby-doom (0.8, 0.0.7)
            Ruby-DOOM provides a scripting API for creating DOOM
            maps. It also provides higher-level APIs to make map
            creation easier.
        
title: Searching remotely installable gems - body: | When you run (as root, if appropriate and necessary)
gem install --remote progressbar
        # shortcut: gem i -r progressbar
the _progressbar_ gem will be installed on your computer. Notice that you don't need to specify the version, but you can if you want to. It will default to the last version available.
gem ins -r progressbar-0.0.3
or
gem ins -r progressbar --version '> 0.0.1'
In both cases, the output is simply: Attempting remote installation of 'progressbar' Successfully installed progressbar, version 0.0.3 RubyGems allows you to have multiple versions of a library installed and choose in your code which version you wish to use. Useful extra options for installation are --gen-rdoc for generating the gem's RDoc API documentation, and --run-tests to run the gem's unit tests, if any. Note too that when you remotely install a gem, it will download and install any specified dependencies. Try installing *copland* and see that it prompts you to accept *log4r* as well (if it's not already installed). title: Installing a remote gem - body: | When you run
gem specification  progressbar
        # shortcut: gem spec progressbar
you will see all the details of the ''progressbar'' gem. Sample output:
          --- !ruby/object:Gem::Specification
          rubygems_version:"1.0\"
          name: progressbar
          version: !ruby/object:Gem::Version
            version: 0.0.3
          date: 2004-03-20 20:03:00.679937 +11:00
          platform:
          summary: "Ruby/ProgressBar is a text progress bar library for Ruby.  It can
                    indicate progress with percentage, a progress bar, and estimated
                    remaining time."
          require_paths:
            - lib
          files:
            - sample/test.rb
            - lib/progressbar.rb
            - docs/progressbar.en.rd
            - docs/progressbar.ja.rd
            - ChangeLog
          autorequire: progressbar
          author: Satoru Takabayashi
          email: satoru@namazu.org
          homepage: http://namazu.org/~satoru/ruby-progressbar/
        
Some interesting information includes the author's details, the version and description of the gem. There is also important technical information for RubyGems to use this gem properly. This includes the list of files included, where to include files from, and what to require by default (more on this later). title: Looking at an installed gem - body: | If we've finished with *progressbar*, we can uninstall it. gem uninstall progressbar Sample output: Successfully uninstalled progressbar version 0.0.3 If there are more than one version of a gem installed, the gem command will ask you which version to delete. If there are other gems that depend upon the gem being uninstalled, and if there is no other way to satisfy that dependency, then the user will be will be given a warning and allowed to cancel the uninstall. title: Uninstalling a gem - body: | It's easy:
gem query --local
        # shortcut: 'gem q -L'
title: Listing all installed gems - body: | You've no doubt noticed the --local and --remote options on most of the command lines shown so far. If you don't specify either of these, then gem will (usually) try ''both'' a local and remote operation. For example: gem ins rake # Attempt local installation; go remote if necessary gem list -b ^C # List all local AND remote gems beginning with "C" title: A note on local and remote operations - body: | You can run your own gem server. This means other people can (potentially) install gems ''from your computer''. And as a side-effect of that, you can view your installed gems through your web browser. Just run gem_server and point your browser to "http://localhost:8808":http://localhost:8808. You'll be able to view the documentation for each gem, as long as you asked for it to be generated when you installed it. title: Browsing all installed gems and their documentation - body: | If you want to always generate RDoc documentation and run unit tests for each gem you install, then you can specify these command-line options in a config file (.gemrc in your home directory).
gem: --gen-rdoc --run-tests
There are other things you can achieve with a config file (RDoc parameters, GEMPATH settings). See GemReference for the details. title: Using a config file - body: | gem check --alien will report on any rogue (unmanaged) files in the RubyGems repository area. gem check --verify progressbar will check that the installed ''progressbar'' gem is valid against its own checksum. title: Other features - title: Installing RubyGems page: - body: | Get it from "RubyForge":http://rubyforge.org/frs/?group_id=126 (http://rubyforge.org/frs/?group_id=126) and run (as root, if appropriate and necessary) ruby setup.rb It's easy. It installs the required library files and the *gem* command. This command gives us the power to do everything else in this document, except distribute gems (for now!). *Debian Linux*: Debian does not automatically include all the standard Ruby libararies in the basic Ruby package. As a result, you may need to ''apt-get'' libyaml-ruby and libzlib-ruby before you can install rubygems. title: Installing RubyGems - body: | If a user does not have access to the standard installation location (typically @/usr/local/lib/ruby@), then they have the option of installing RubyGems in a alternate location. Note that if you can't install RubyGems in the standard location, then you probably can't install gems in the standard gem repository location either. You need to specifiy a non-standard gem repository location via the GEM_HOME environment variable. Use the following to install RubyGems in a user directory (here called @/home/mystuff@) with a repository named @/home/mygemrepository@): $ export GEM_HOME=/home/mygemrepository $ ruby setup.rb config --prefix=/home/mystuff $ ruby setup.rb setup $ ruby setup.rb install *Notes:* # The @export@ command is @ksh@ specific. Use the appropriate command for your OS. For example windows users would probably say:
set GEM_HOME=/home/mygemrepository
# Make sure you add @/home/mystuff/bin@ to your path so that the @gem@ command can be found. # Make sure you add the @GEM_HOME@ setup to your profile, so that RubyGems can find the location of your gem repository. # If you want the gem repository to reside inside the install directory, we recommend setting @GEM_HOME@ _prefix_dir_/@gems@. (where _prefix_dir_ is given as the valud of @--prefix@ in the config step) title: Installing RubyGems in a User Directory - body: |- h3. Modern Versions of RubyGems If your RubyGems version is 0.8.5 or later, you can upgrade to the latest version with: gem update --system Don't forget to use sudo if your system requires root access to install ruby libraries. h3. Prior to RubyGems 0.8.5 If you current version of RubyGems is prior to version 0.8.5, then use the following commands: gem install rubygems-update update_rubygems h3. Manual Upgrades Download the latest RubyGems tar or zip file and following the instructions for "Installing RubyGems":http://docs.rubygems.org/read/chapter/3#page13. title: Updating RubyGems - body: |- Now that you have RubyGems installed, you should be ready to run applications using gems, right? Well, almost. You have one more decision to make: How to let Ruby programs know to use the gems repository. You see, because the of versioned nature of the gems repository, RubyGems doesn't store the library files directly in standard library search path. It adds the necessary gem packages to the library seach path as needed at run time. This means that RubyGems must be loaded before any gem libraries are accessable. h3. The Hard Way The most direct way to make RubyGems available is to just require it in the source code:
           require 'rubygems'
           require 'some_gem_library'
           # ...
        
The big problem with this approach is that you don't want to make this change to every single Ruby program you download! While ok for quick scripts you write yourself, this is not the way to go. h3. Using the @-rubygems@ Command Line Option To avoid modifying all the Ruby programs you install, you could tell the @ruby@ interpreter to preload ruby gems before running other software. You can easily do this by giving the @ruby@ command a @-rubygems@ option each time you run a program. ruby -rubygems my_program_that_uses_gems This works, and avoids changing installed software, but is a pain to type all the time. Fortunately there is another option. h3. Using @RUBYOPT@ By setting the @RUBYOPT@ environment variable to the value @rubygems@, you tell Ruby to load RubyGems every time it starts up. This is similar to the @-rubygems@ options above, but you only have to specify this once (rather than each time you run a Ruby script). Unix users will want to put the following line in their @.profile@ (or equivalent): export RUBYOPT=rubygems Windows users will want to set the RUBYOPT environment variable using the appropriate sysetm utility. (On XP you can find it under Settings / Control Panel / System. Click the advanced tab and then the "Environment Variables" button near the bottom. Note that the one-click installer will set up RUBYOPT for you automatically (unless you request it not be done). h3. The Future The need to preload the RubyGems software is one of the biggest drawbacks to RubyGems' versioned software approach. The RubyGems team is investigating ways of making this issue much less onerous. In the meantime, enjoy RubyGems. title: Post-install -- Setting Up the RubyGems Environment - title: Coding With RubyGems page: - body: | Here we demonstrate the use of the *progressbar* gem. This library may use terminal features that are not available in your system. If you wish, enter the following code into a file and run it. (Note that you must require the rubygems library before executing this code, as detailed in chapter 3 of this manual.)
        require 'progressbar'
        
        bar = ProgressBar.new("Example progress", 50)
        total = 0
        until total >= 50
          sleep(rand(2)/2.0)
          increment = (rand(6) + 3)
          bar.inc(increment)
          total += increment
        end
        
Here is a "screenshot" of the partially complete progress bar. Example progr: 29% |ooooooooooo | ETA: 00:00:04 The first line of the program requires the progressbar library file. RubyGems will look for the @progressbar.rb@ file in the standard library locations. If not found, it will look through its gem repository for a gem that contains @progressbar.rb@. If a gem is used, RubyGems attempts to use the latest installed version by default. Note that the program was able to use the latest available installed gem by default _without_ any explicit action in the code. The developer may develop a library without worrying about using RubyGems. However, to _run_ the code, the environment does need to be "gem enabled". See "Setting Up the RubyGems Environment":http://docs.rubygems.org/read/chapter/3#page70 for details on how to make this happen. title: Using a gem in your code - body: | The distinguishing feature of RubyGems is the ability to use versioned libraries when running an application. How do we take advantage of versioning. h3. Explicit Versioning To explicitly use a particular version of a library, you need to use the @require_gem@ command. This command specifies the name of a gem package and the version you wish to have loaded. For example, suppose your application uses RedCloth, but needs a version of RedCloth in the 3.x series. You can include explcitly in your code:
          require 'rubygems'
          require_gem 'RedCloth', '~> 3.0'
        
RubyGems will select the latest installed version of the RedCloth software that has a version number in the 3.x series. If no such software is found, a exception is generated. h3. Planning Ahead Rather than spread your version requirements all over your code, it is best to gather them in one location to make it easy to maintain. The Rails application framework is a good example. You will find an environment file in the config directory of any (recent) Rails application. The environment file, in part, contains the following lines:
        # ...
        require 'rubygems'
        require_gem 'activesupport'
        require_gem 'activerecord'
        require_gem 'actionpack'
        require_gem 'actionmailer'
        require_gem 'actionwebservice'
        require_gem 'rails'
        # ...
        
The lines will load the most recent available version of the Rails software. If the most current version is not appropriate (perhaps your ISP has upgraded to an incompatible version of Rails and you haven't converted your web app yet), then all you need to do is edit @environment.rb@ to be something like:
        # ...
        require 'rubygems'
        require_gem 'activerecord', '= 1.4.0'
        require_gem 'actionpack', '= 1.2.0'
        require_gem 'actionmailer', '= 0.5.0'
        require_gem 'rails', '= 0.9.3'
        # ...
        
Now your webapp will use an older version of Rails without interfering with anyone else's use of the newer version. title: Using Explicit Versions - body: |- Using explicit versions in your code is a nice way to make sure you get exactly the libraries you want. The downside is that your code becomes dependent upon the presence of RubyGems, even when no explicit versions are required. Here is an easy way to avoid explicit dependencies on RubyGems without giving up the ability to handle versions upon request. We move the version requests into a configuration file (we will use Yaml for this example, but that is not critical to the solution). Execute the following code early in your program _before_ you require any non-core[1] libraries.
        config = open("config.yml") { |f| YAML.load(f.read) }
        if config[:gems]
          require 'gemconfigure'
          Gem.configure(config[:gems])
        end
        
@gemconfigure@ is a lightweight library file provided by RubyGems (lightweight in that it only defines a single method in the @Gem@ module, it does not bring in the entire RubyGems system into memory). If your config file has gem information (indicated by the presence of @:gems@ entry in the hash table), then the @gemconfigure@ file is loaded and the @Gem.configure@ method is given the configuration information. @Gem.configure@ walks through the a list of name/version pairs from the config and loads the gems specified with the requested version numbers. The RubyGems software is only loaded when @Gem.configure@ determines that an actual versioned gem is required. This five line code snippet allows an application to use versioning if requested in a config file, but have no dependencies on RubyGems at all if no versioned gems are requested. The @gemconfigure@ file is not even loaded unless the config file requests versioning. For reference, the Yaml config file might look something like this:
        ---
        :gems:
          - ['RedCloth', '~> 3.0']
          - ['rubyzip', '= 0.5.5']
        
fn1. I.e. any libraries that are not delivered with the Ruby language. title: Using Configured Versions - title: Specifying Versions page: - body: | The concept of a version is central to the RubyGems packaging scheme. Every gem package is assigned a version string consisting of digits and periods (e.g. "@1.3.122@"). The @gem@ command line program and the @require_gem@ Ruby command both take version constraint arguments. These arguments restrict the range of versions that are acceptable to the commands. For example, if you want in install verion 0.4.14 of the @rake@ gem, you can say:
          gem install --remote rake --version "0.4.14"
        
title: Basic Versions - body: | If you don't care about the _exact_ version of @rake@, but want to make sure you get something later than version 0.4.10, you can say:
  gem install --remote rake --version "> 0.4.10"
In fact, any of the standard comparison operators can be used for the version constraint. Here are the available operators: = Equals version != Not equal to version > Greater than version < Less than version >= Greater than or equal to <= Less than or equal to ~> Approximately greater than (see "Pessimistic Version Constraint" below) Here are some examples: "> 1.1" "= 4.56.4" If no version constraint operator is specified, RubyGems will assume that "=" was intended. title: Advanced Versioning - body: | If your project is using the "Rational Versioning Policy":/read/chapter/7 to assign version numbers, then your users can take advantage of that fact to carefully specify exactly what versions of your software should work with their system. For example, suppose you have the following releases ... * Version 2.1.0 -- Baseline * Version 2.2.0 -- Introduced some new (backward compatible) features. * Version 2.2.1 -- Removed some bugs * Version 2.2.2 -- Streamlined your code * Version 2.3.0 -- More new features (but still backwards compatible). * Version 3.0.0 -- Reworked the interface. Code written to verion 2.x _might_ not work. Your clients have validated that version 2.2.0 works with their software, but version 2.1.0 doesn't have a feature they need). Their require line would look like this ... require_gem 'library', '>= 2.2.0' This is called an OptimisticVersionConstraint. They are optimistic that the incompatible changes introduced in version 3.0 will still work with their software. They have no assurance of this (most likely verion 3.0 wasn't written when they wrote the require_gem line). But they are willing to take the chance. Some other clients of your library are not so hopeful. They fully expect that new interfaces will break their software, so they want to guard against accidently using the new interfaces. They use a PessimisticVersionConstraint that explicitly excludes your version 3.0. require_gem 'library', '>= 2.2.0', '< 3.0' Doing this is cumbersome, so RubyGems provides a pessimistic operator ~~~> (read: approximately greater than). Using the pessimistic operator, we get: require_gem 'library', '~> 2.2' Notice that we only include 2 digits of the version. The operator will drop the final digit of a version, then increment the remaining final digit to get the upper limit version number. (Remember, you can alway supply an explicit upper limit if the pessimistic operator is too limited for you). title: Pessimistic Version Constraint - title: Versioning Policies page: - body: | A versioning policy is merely a set of simple rules governing how version numbers are allocated. It can be very simple (e.g. the version number is a single number starting with 1 and incremented for each successive version), or it can be really strange (Knuth's[#knuth] TeX project had version numbers: 3, 3.1, 3.14, 3.141, 3.1415; each successive version added another digit to PI). title: What's a Versioning Policy - body: | Because RubyGems provides support for version comparisons, we want to pick a policy that works well with the RubyGems comparisons and gives the end user what they expect. We call such a policy "rational". Also, if we call non-working policies "irrational", then we apply a little bit of social engineering to gently prod offenders to conform. By the way, Knuth's versioning policy (mentioned above) is not only irrational, it is also transcendental. title: Why is this one ''Rational''? - body: | Users expect to be able to specify a version constraint that gives them some reasonable expectation that new versions of a library will work with their software if the version constraint is true, and not work with their software if the version constraint is false. In other words, the perfect system will accept all compatible versions of the library and reject all incompatible versions. Libraries change in 3 ways (well, more than 3, but stay focused here!). # The change may be an implementation detail only and have no effect on the client software. # The change may add new features, but do so in a way that client software written to an earlier version is still compatible. # The change may change the public interface of the library in such a way that old software is no longer compatible. Some examples are appropriate at this point. Suppose I have a Stack class that supports a push and a pop method. Examples of Category 1 changes: * Switch from an array based implementation to a linked-list based implementation. * Provide an automatic (and transparent) backing store for large stacks. Examples of Category 2 changes might be: * Add a depth method to return the current depth of the stack. * Add a top method that returns the current top of stack (without changing the stack). * Change push so that it returns the item pushed (previously it had no usable return value). Examples of Category 3 changes might be: * Changes pop so that it no longer returns a value (you must use top to get the top of the stack). * Rename the methods to push_item and pop_item. title: Ways Libraries Change - body: | The RationalVersioningPolicy provides the following guidelines: * Versions shall be represented by three non-negative integers, separated by periods (e.g. 3.1.4). The first integers is the '''major''' version number, the second integer is the '''minor''' version number, and the third integer is the '''build''' number. * A category 1 change (implementation detail) will increment the build number. * A category 2 change (backwards compatible) will increment the minor version number and reset the build number. * A category 3 change (incompatible) will increment the major build number and reset the minor and build numbers. * Any ''public'' release of a gem should have a different version. Normally that means incrementing the build number. This means a developer can generate builds all day long for himself, but as soon as he/she makes a public release, the version must be updated. That's it. It's not too difficult. title: Ok, Give me the Details - body: | Let's work through a project lifecycle using our Stack example from above. * Version 0.0.1: The initial Stack class is release. * Version 0.0.2: Switched to a linked=list implementation because it is cooler. * Version 0.1.0: Added a depth method. * Version 1.0.0: Added top and made pop return nil (pop used to return the old top item). * Version 1.1.0: push now returns the value pushed (it used it return nil). * Version 1.1.1: Fixed a bug in the linked list implementation. * Version 1.1.2: Fixed a bug introduced in the last fix. Client A needs a stack with basic push/pop capability. He writes to the original interface (no top), so his version constraint looks like ... require_gem 'stack', '>= 0.0' Essentially, any version is OK with Client A. An incompatible change to the library will cause him grief, but he is willing to take the chance (we call Client A optimistic). Client B is just like Client A except for two things: (1) He uses the depth method and (2) he is worried about future incompatibilities, so he writes his version constraint like this: require_gem 'stack', '>=0.1', '< 1.0' The depth method was introduced in version 0.1.0, so that version or anything later is fine, as long as the version stay below version 1.0 where incompatibilities are introduced. We call Client B pessimistic because he is worried about incompatible future changes (it is OK to be pessimistic!). Client B could have written the his pessimistic constraint like this ... require_gem 'stack', '~> 0.1' This uses the pessimistic comparison operator and short hand for the previous version (see PessimisticVersionConstraint). title: Examples - body: | Although RubyGems provides no mechanism to enforce versioning policy, we feel that this is an important issue. And it will become more important as the number of gems increases and the number of versions proliferate. So we strongly encourage developers to follow the RationalVersioningPolicy, or at least one of the VersioningPolicyVariations. title: Summary - title: Creating Your Own Gem page: - body: | This is a skimpy overview; see the DeveloperGuide for the real meat. Let's say we have a package called ''rmagic'' which is at version 2.1. Building a gem involves two steps: * creating a _gem specification file_ (rmagic.gemspec), which is Ruby code; and * running gem build my.gemspec to create the gem file (rmagic-2.1.gem) The specification contains Ruby code to create a Gem::Specification object, which defines all of the information we saw above in Looking at an installed gem. The gem file contains everything needed to install itself on another computer, including the specification and all the file data. See? Building a gem is very easy! *Note:* "rake":http://rake.rubyforge.org (http://rake.rubyforge.org) is a big help in creating gem files in a project setting, where the version number is always changing, etc. title: Building a gem - title: Distributing Gems page: - body: "Make your gem available on a web site for FTP site for downloading. Users can get the gem with conventional internet tools (e.g. browsers and FTP clients) and do a local install. " title: Conventional Distribution - body: | By running @gem_server@ on your box, you can serve your entire set of installed gems to anyone. Further instructions *TBD*. title: Remote Serving - body: | You can make a gem available for manual download. "RubyForge":http://rubyforge.org (http://rubyforge.org) will automatically deploy any .gem file you upload to a project download area. I encourage you to get a RubyForge account and start a RubyForge project for your code. Even if you only use the file download area, it provides a mirror for your software for when your main site goes down. title: Distributing on RubyForge - title: Signing Your Gems page: - body: |- p(((. This chapter is provided by Paul Duncan, the author of the signing patch. RubyGems version 0.8.11 and later supports adding cryptographic signatures to gems. The section below is a step-by-step guide to using signed gems and generating your own. title: Overview - body: | In order to start signing your gems, you'll need to build a private key and a self-signed certificate. Here's how:
          # build a private key and certificate for gemmaster@example.com
          $ gem cert --build gemmaster@example.com
        
This could take anywhere from 5 seconds to 10 minutes, depending on the speed of your computer (public key algorithms aren't exactly the speediest crypto algorithms in the world). When it's finished, you'll see the files "gem-private_key.pem" and "gem-public_cert.pem" in the current directory. First things first: take the "gem-private_key.pem" file and move it somewhere private, preferably a directory only you have access to, a floppy (yuck!), a CD-ROM, or something comparably secure. Keep your private key hidden; if it's compromised, someone can sign packages as you (note: PKI has ways of mitigating the risk of stolen keys; more on that later). Now, let's sign an existing gem. I'll be using my Imlib2-Ruby bindings, but you can use whatever gem you'd like. Open up your existing gemspec file and add the following lines:
          # signing key and certificate chain
          s.signing_key = '/mnt/floppy/gem-private_key.pem'
          s.cert_chain  = ['gem-public_cert.pem']
        
(Be sure to replace "/mnt/floppy" with the ultra-secret path to your private key). After that, go ahead and build your gem as usual. Congratulations, you've just built your first signed gem! If you peek inside your gem file, you'll see a couple of new files have been added:
          $ tar tf tar tf Imlib2-Ruby-0.5.0.gem 
          data.tar.gz
          data.tar.gz.sig
          metadata.gz
          metadata.gz.sig
        
Now let's verify the signature. Go ahead and install the gem, but add the following options: "-P HighSecurity", like this:
          # install the gem with using the security policy "HighSecurity"
          $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
        
The -P option sets your security policy -- we'll talk about that in just a minute. Eh, what's this?
          Attempting local installation of 'Imlib2-Ruby-0.5.0.gem'
          ERROR:  Error installing gem Imlib2-Ruby-0.5.0.gem[.gem]: Couldn't
          verify data signature: Untrusted Signing Chain Root: cert =
          '/CN=gemmaster/DC=example/DC=com', error = 'path
          "/root/.rubygems/trust/cert-15dbb43a6edf6a70a85d4e784e2e45312cff7030.pem"
          does not exist'
        
The culprit here is the security policy. RubyGems has several different security policies. Let's take a short break and go over the security policies. Here's a list of the available security policies, and a brief description of each one: * NoSecurity - Well, no security at all. Signed packages are treated like unsigned packages. * LowSecurity - Pretty much no security. If a package is signed then RubyGems will make sure the signature matches the signing certificate, and that the signing certificate hasn't expired, but that's it. A malicious user could easily circumvent this kind of security. * MediumSecurity - Better than LowSecurity and NoSecurity, but still fallible. Package contents are verified against the signing certificate, and the signing certificate is checked for validity, and checked against the rest of the certificate chain (if you don't know what a certificate chain is, stay tuned, we'll get to that). The biggest improvement over LowSecurity is that MediumSecurity won't install packages that are signed by untrusted sources. Unfortunately, MediumSecurity still isn't totally secure -- a malicious user can still unpack the gem, strip the signatures, and distribute the gem unsigned. * HighSecurity - Here's the bugger that got us into this mess. The HighSecurity policy is identical to the MediumSecurity policy, except that it does not allow unsigned gems. A malicious user doesn't have a whole lot of options here; he can't modify the package contents without invalidating the signature, and he can't modify or remove signature or the signing certificate chain, or RubyGems will simply refuse to install the package. Oh well, maybe he'll have better luck causing problems for CPAN users instead :). So, the reason RubyGems refused to install our shiny new signed gem was because it was from an untrusted source. Well, my code is infallible (hah!), so I'm going to add myself as a trusted source. Here's how:
            # add trusted certificate
            gem cert --add gem-public_cert.pem
        
I've added my public certificate as a trusted source. Now I can install packages signed my private key without any hassle. Let's try the install command above again:
          # install the gem with using the HighSecurity policy (and this time
          # without any shenanigans)
          $ sudo gem install Imlib2-Ruby-0.5.0.gem -P HighSecurity
        
This time RubyGems should accept your signed package and begin installing. While you're waiting for RubyGems to work it's magic, have a look at some of the other security commands:
          Usage: gem cert [options]
        
          Options:
            -a, --add CERT          Add a trusted certificate.
            -l, --list              List trusted certificates.
            -r, --remove STRING     Remove trusted certificates containing STRING.
            -b, --build EMAIL_ADDR  Build private key and self-signed certificate 
                                    for EMAIL_ADDR.
            -C, --certificate CERT  Certificate for --sign command.
            -K, --private-key KEY   Private key for --sign command.
            -s, --sign NEWCERT      Sign a certificate with my key and certificate.
        
(By the way, you can pull up this list any time you'd like by typing "gem cert --help") Hmm. We've already covered the "--build" option, and the "--add", "--list", and "--remove" commands seem fairly straightforward; they allow you to add, list, and remove the certificates in your trusted certificate list. But what's with this "--sign" option? To answer that question, let's take a look at "certificate chains", a concept I mentioned earlier. There are a couple of problem s with self-signed certificates: first of all, self-signed certificates don't offer a whole lot of security. Sure, the certificate says Yukihiro Matsumoto, but how do I know it was actually generated and signed by Matz himself unless he gave me the certificate in person? The second problem is scalability. Sure, if there are 50 gem authors, then I have 50 trusted certificates, no problem. What if there are 500 gem authors? 1000? Having to constantly add new trusted certificates is a pain, and it actually makes the trust system less secure by encouraging RubyGems users to blindly trust new certificates. Here's where certificate chains come in. A certificate chain establishes an arbitrarily long chain of trust between an issuing certificate and a child certificate. So instead of trusting certificates on a per-developer basis, we use the PKI concept of certificate chains to build a logical hierarchy of trust. Here's a hypothetical example of a trust hierarchy based (roughly) on geography:
                                --------------------------
                                | rubygems@rubyforge.org |
                                --------------------------
                                            |
                          -----------------------------------
                          |                                 |
              ----------------------------    -----------------------------
              | seattle.rb@zenspider.com |    | dcrubyists@richkilmer.com |
              ----------------------------    -----------------------------
                   |                |                 |             |
            ---------------   ----------------   -----------   --------------
            | alf@seattle |   | bob@portland |   | pabs@dc |   | tomcope@dc |
            ---------------   ----------------   -----------   --------------
        
Now, rather than having 4 trusted certificates (one for alf@seattle, bob@portland, pabs@dc, and tomecope@dc), a user could actually get by with 1 certificate: the "rubygems@rubyforge.org" certificate. Here's how it works: I install "Alf2000-Ruby-0.1.0.gem", a package signed by "alf@seattle". I've never heard of "alf@seattle", but his certificate has a valid signature from the "seattle.rb@zenspider.com" certificate, which in turn has a valid signature from the "rubygems@rubyforge.org" certificate. Voila! At this point, it's much more reasonable for me to trust a package signed by "alf@seattle", because I can establish a chain to "rubygems@rubyforge.org", which I do trust. And the "--sign" option allows all this to happen. A developer creates their build certificate with the "--build" option, then has their certificate signed by taking it with them to their next regional Ruby meetup (in our hypothetical example), and it's signed there by the person holding the regional RubyGems signing certificate, which is signed at the next RubyConf by the holder of the top-level RubyGems certificate. At each point the issuer runs the same command:
          # sign a certificate with the specified key and certificate
          # (note that this modifies client_cert.pem!)
          $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem \
              --sign client_cert.pem
        
Then the holder of issued certificate (in this case, our buddy "alf@seattle"), can start using this signed certificate to sign RubyGems. By the way, in order to let everyone else know about his new fancy signed certificate, "alf@seattle" would change his gemspec file to look like this:
          # signing key (still kept in an undisclosed location!)
          s.signing_key = '/mnt/floppy/alf-private_key.pem'
          
          # certificate chain (includes the issuer certificate now too)
          s.cert_chain  = ['/home/alf/doc/seattlerb-public_cert.pem',
                           '/home/alf/doc/alf_at_seattle-public_cert.pem']
        
Obviously, this RubyGems trust infrastructure doesn't exist yet (I just wrote the patch, for cripes sake!). Also, in the "real world" issuers actually generate the child certificate from a certificate request, rather than sign an existing certificate. And our hypothetical infrastructure is missing a certificate revocation system. These are that can be fixed in the future... I'm sure your new signed gem has finished installing by now (unless you're installing rails and all it's dependencies, that is ;D). At this point you should know how to do all of these new and interesting things: * build a gem signing key and certificate * modify your existing gems to support signing * adjust your security policy * modify your trusted certificate list * sign a certificate If you've got any questions, feel free to contact me at the email address below. title: Walkthrough - body: | Here's a brief summary of the certificate-related command line options:
          gem install
            -P, --trust-policy POLICY        Specify gem trust policy.
        
          gem cert
            -a, --add CERT                   Add a trusted certificate.
            -l, --list                       List trusted certificates.
            -r, --remove STRING              Remove trusted certificates containing 
                                             STRING.
            -b, --build EMAIL_ADDR           Build private key and self-signed 
                                             certificate for EMAIL_ADDR.
            -C, --certificate CERT           Certificate for --sign command.
            -K, --private-key KEY            Private key for --sign command.
            -s, --sign NEWCERT               Sign a certificate with my key and 
                                             certificate.
        
        
        A more detailed description of each options is available in the walkthrough above.

      title: Command-Line Options
    - body: |-
        The .pem files generated by --build and --sign are just basic OpenSSL PEM files.  Here's a couple of useful commands for manipulating them:
        
        
          # convert a PEM format X509 certificate into DER format:
          # (note: Windows .cer files are X509 certificates in DER format)
          $ openssl x509 -in input.pem -outform der -out output.der
        
          # print out the certificate in a human-readable format:
          $ openssl x509 -in input.pem -noout -text
        
And you can do the same thing with the private key file as well:
          # convert a PEM format RSA key into DER format:
          $ openssl rsa -in input_key.pem -outform der -out output_key.der
        
          # print out the key in a human readable format:
          $ openssl rsa -in input_key.pem -noout -text
        
title: OpenSSL Reference - body: |- * right now I'm using Gem.user_home + '.gem/trust' for the trusted cert list. There's no way to define a system-wide trust list. * custom security policies (from a YAML file, etc) * Simple method to generate a signed certificate request * Support for OCSP, SCVP, CRLs, or some other form of cert status check (list is in order of preference) * Support for encrypted private keys * Some sort of semi-formal trust hierarchy (see long-winded explanation above) * Path discovery (for gem certificate chains that don't have a self-signed root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the MediumSecurity and HighSecurity policies) * Better explanation of X509 naming (ie, we don't have to use email addresses) * possible alternate signing mechanisms (eg, via PGP). This could be done pretty easily by adding a :signing_type attribute to the gemspec, then add the necessary support in other places * honor AIA field (see note about OCSP above) * maybe honor restriction extensions? * might be better to store the certificate chain as a PKCS#7 or PKCS#12 file, instead of an array embedded in the metadata. ideas? * possibly embed signature and key algorithms into metadata (right now they're assumed to be the same as what's set inGem::Security::OPT) title: Bugs/TODO - body: |- Paul Duncan (pabs@pablotron.org) http://pablotron.org/ title: About the Author - title: Supporting Software page: - body: |- The @gemwhich@ script works much like the unix shell 'which' command. Given a include file reference, it will locate that file in ruby libraries and gem repositories and display the file path for the file. For example, if you would like to know where the rake/testtask file might be located, just type:
        $ gemwhich rake/testtask
        /usr/local/lib/ruby/gems/1.8/gems/rake-0.4.15/lib/rake/testtask.rb
        
@gemwhich@ will work with regular (non-gem) Ruby libraries as well.
        $ gemwhich socket
        /usr/local/lib/ruby/1.8/i686-linux/socket.so
        
h3. Usage
        gemwhich -- Find the location of a library module.
        
        Usage: gemwhich [options] libname...
            -v, --verbose       Enable verbose output
            -h, --help          Display this help message
        
title: gemwhich script - body: | (new in version 0.9.0) The @gemlock@ script will generate a series of @require_gem@ commands that will lock down an application or library to a particular version of their dependent gems. For example, if you wish to lock down a particular version of the Rails library, use:
          $ gemlock rails-1.0.0
          require "rubygems"
          require_gem 'rails', '= 1.0.0'
          require_gem 'rake', '= 0.7.0.1'
          require_gem 'activesupport', '= 1.2.5'
          require_gem 'activerecord', '= 1.13.2'
          require_gem 'actionpack', '= 1.11.2'
          require_gem 'actionmailer', '= 1.1.5'
          require_gem 'actionwebservice', '= 1.0.0'
        
@gemlock@ will find all the direct and indirect gems required by rails-1.0.0 and specify the most recent, currently installed version of those gems. The output should be place in the application (or library) will it will be run *before* any other require statement in the program. If your application depends on more than one gem, just list all the gems in the command line and @gemlock@ will display the locking commands for all of them. h3. Usage
          Usage: bin/gemlock [options] GEM_NAME-VERSION...
        
          Where options are:
            -v, --verbose                    Verbose output
            -s, --[no-]strict                Fail if unable to satisfy a dependency
            -h, --help                       Show this message
            -V, --version                    Show version
        
title: gemlock script body: | RubyGems is the premier ruby packaging system. It provides: * A standard format for destributing Ruby programs and libraries. * An easy to use tool for managing the installation of gem packages. * A gem server utility for serving gems from any machine where RubyGems is installed. title: RubyGems User Guide