Bundler

Puppet is just the fisrt dependency of our future modules. As we continue our journey to a Test Driven work flow, other gems will come into play.

I we want to manage these development dependencies in an orderly way we need a way to declare them.

Bundler is gem by itself. It's job is to manage the tricky business of gem dependencies. Nowadays it is the Ruby Community's default way of managing dependencies.

Installing Bundler

Pick your favorite gemset and install it by running the gem install GEMNAME command.

vagrant:$ rvm use 2.2.1
vagrant:$ gem install bundler

Fetching: bundler-1.10.6.gem (100%)
Successfully installed bundler-1.10.6
Parsing documentation for bundler-1.10.6
Installing ri documentation for bundler-1.10.6
Done installing documentation for bundler after 3 seconds
1 gem installed

Gemfile

A [Gemfile](http://bundler.io/gemfile.html) [2] is Bundler's way of declaring your project's dependencies.

Select your RVM manged project and add a default Gemfile by running the bundle init command.

vagrant:$ mkdir ~/my-project
vagrant:$ echo '2.2.1' > ~/my-project/.ruby-version
vagrant:$ echo 'puppet-4.2.1' > ~/my-project/.ruby-gemset
vagrant:$ cd ~/my-project
vagrant:$ bundle init
Writing new Gemfile to /home/vagrant/my-project/Gemfile

This is how your default Gemfile looks like:

# /home/vagrant/my-project/Gemfile

# A sample Gemfile
source "https://rubygems.org"

# gem "rails"

There are two main sections in a Gemfile.

First is the source. This is a URL where the gems that your project needs are hosted. By default gems are hosted in the public rubygems.org [3] repository. But you can change this to a private repository if you need to.

The second section is the gems declaration section. In here you will write the name of your gems, the version required by them. Bundler will take care of determining the dependency tree for all the declared gems and their dependencies.

Here is an example taken from the Bundler site on how to declare gem versions.

gem 'nokogiri'
gem 'rails', '3.0.0.beta3'
gem 'rack',  '>=1.0'
gem 'thin',  '~>1.1'

Most of the version specifiers, like >= 1.0, are self-explanatory. The specifier ~> has a special meaning, best shown by example. ~> 2.0.3 is identical to >= 2.0.3 and < 2.1. ~> 2.1 is identical to >= 2.1 and < 3.0. ~> 2.2.beta will match prerelease versions like 2.2.beta.12. [4]

Update and save your Gemfile to include puppet 4.2.1 as it's only dependency.

# /home/vagrant/my-project/Gemfile

source "https://rubygems.org"

gem "puppet", "4.2.1"

Install dependencies

Now that you have a valid Gemfile it is time to install your gems.

Run the bundle install command in the same directory that contains your Gemfile. Bundle will query the source you specified for the version of the gem you declared and will also find it's dependencies.

vagrant:$ cd ~/my-project
vagrant:$ ls
Gemfile

vagrant:$ bundle install
Fetching gem metadata from https://rubygems.org/...........
Fetching version metadata from https://rubygems.org/..
Resolving dependencies...
Installing CFPropertyList 2.2.8
Installing facter 2.4.4
Installing json_pure 1.8.2
Installing hiera 3.0.1
Installing puppet 4.2.1
Using bundler 1.8.4
Bundle complete! 1 Gemfile dependency, 6 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

You can see the gems installed by in your bundle by running bundle show in the directory that holds your Gemfile.

Notice that Bundler has created a new file named Gemfile.lock. This file contains the real manifest of the dependency tree. In it you will see a list of the gems you declared in the Gemfile, as well as their dependencies.

vagrant:$ cd ~/my-project
vagrant:$ cat Gemfile.lock
GEM
  remote: https://rubygems.org/
  specs:
    CFPropertyList (2.2.8)
    facter (2.4.4)
      CFPropertyList (~> 2.2.6)
    hiera (3.0.1)
      json_pure
    json_pure (1.8.2)
    puppet (4.2.1)
      facter (> 2.0, < 4)
      hiera (>= 2.0, < 4)
      json_pure

PLATFORMS
  ruby

DEPENDENCIES
  puppet (= 4.2.1)

Updating dependencies

Use the bundle update command to install the latest version available of your declared gems.

Word of caution

Always declare the specific version of each gem your project requires. Leaving version numbers open can lead to many unfortunate incidents that tend to happen when you are short of time and sleep.

If you will like to relax your version numbers I recommend using the spermy operator ~>. Wich will allow you to update to a higher patch version of your gem, but will not update to a minor one. This allows you to get the latest bug patches without accepting any new features that might break your code.

An updated version of your Gemfile might look like:

# /home/vagrant/my-project/Gemfile

source "https://rubygems.org"

gem "puppet", "~>4.2.1"

Now you could run the bundle update command to get a new version of Puppet. Bundler will download and install any new version starting with 4.2.1 and ending with 4.2.99. But you will never receive anything higher like 4.3 or 5.


[1] Bundler - The best way to manage a Ruby application's gems: http://bundler.io/

[2] Gemfile: http://bundler.io/gemfile.html

[3][4] rubygems.org - Find, install, and publish RubyGems: https://rubygems.org/