Tumbler

Let’s make gem development fun! Tumbler provides common gem management tasks using a common set of ‘best practices’ out of the box.

Gem Guidelines

Tumbler was built to help developers create and manage gems using a common set of ‘best practices’ out of the box. Tumbler also makes a number of assumptions about your workflow:

  • Gem uses directly edited dynamic gemspecs

  • Gem uses Git to manage code source (perhaps on Github)

  • Git tags are created for each new version

  • Gem dependencies are defined using a Gemfile through Bundler

If your gem can follow these guidelines, then Tumbler will automate the entirety of this process for you into rake tasks.

Using Tumbler

Creating Gems

To generate a brand new gem from scratch, execute the following:

$ tumbler your_gem_name

This will generate a skeleton of your gem that you can then easily configure and start building awesome.

Existing Gems

If you have a pre-existing gem which could benefit from Tumbler, you have to a do a few things. Note that if you are generating a new gem using the tumbler command, this will be done for you automatically.

Automatically

To automatically setup your project to use tumbler, simply execute:

tumbler . -u --name gem_name

From inside the gem’s root directory and this will take care of all the details for you. When it’s done updating your gem, review and commit the changes.

Manually

Alternatively, for existing projects, you can set up all the bits needed to make Tumbler work with your gem. This is all handled by a file at the root of your project called Tumbler. A typical Tumbler file should look something like the following:

# Names your gem
gem_name 'my_awesome_gem'

# Use this file to track the version number
version_file 'lib/my_awesome_gem/version.rb'

# Use this file for your changelog
changelog_file 'CHANGELOG'

Your version number can be anything parsable by Versionomy. The changelog will be automatically updated when a new version is released.

The version file should have a constant VERSION or Version which is set to the current version for your gem. A typical version file might look like the following:

# lib/awesome_gem/version.rb
module AwesomeGem #:nodoc
  VERSION = '0.0.1'
end

Next, in your Rakefile, add the following to get access to Tumbler tasks:

require 'tumbler'
Tumbler.use_rake_tasks

If you’d prefer to have the tumbler tasks namespaced, provide use_rake_tasks with a string. For example:

Tumbler.use_rake_tasks('tumbler')

Within your gemspec then, you would have something like tumbler’s gemspec:

# -*- encoding: utf-8 -*-

require 'lib/tumbler'

tumbler = Tumbler::GemspecHelper.new

Gem::Specification.new do |s|
  s.name = tumbler.name
  s.version = tumbler.version

  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
  s.rubyforge_project = tumbler.name
  s.authors = ["Joshua Hull"]
  s.date = tumbler.date
  s.description = "Let's make gem development fun! Tumbler provides common gem management tasks using a common set of 'best practices' out of the box."
  s.summary = "Common gem generation and management tasks"
  s.email = %q{[email protected]}
  s.extra_rdoc_files = tumbler.files('README.rdoc')
  s.files = tumbler.files
  s.homepage = %q{http://github.com/joshbuddy/tumbler}
  s.rdoc_options = ["--charset=UTF-8"]
  s.require_paths = ["lib"]
  s.rubygems_version = %q{1.3.7}
  s.test_files = tumbler.files(/^spec/)
  s.executables = tumbler.bin_files

  # dependencies
  tumbler.inject_dependencies(s)
end

Available Rake Tasks

Once you’ve got Tumbler up and running in your gem, you will have access to the following tasks:

rake gem:build              # Build the gem
rake gem:install            # Install the gem
rake gem:push               # Push the gem
rake version:major:bump     # Bump version from 0.2.12 ->  1.0.0
rake version:minor:bump     # Bump version from 0.2.12 ->  0.3.0
rake version:tiny:bump      # Bump version from 0.2.12 ->  0.2.13
rake version:major:release  # Bump version from 0.2.12 ->  1.0.0 and push
rake version:minor:release  # Bump version from 0.2.12 ->  0.3.0 and push
rake version:tiny:release   # Bump version from 0.2.12 ->  0.2.13 and push
rake version:push           # Push current version into git
rake version:tag            # Tag current version into git

There is a special rake task you can override, 'tumbler:preflight', if you’d like to run specs or do some other task before any of the tumbler tasks get invoked. For instance, to invoke spec before you run your main tasks, you could add:

task 'tumbler:preflight' do
  Rake::Task["spec"].invoke
end

Releasing Your Gem

If you do the following,

rake version:(tiny|minor|major):release

you will bump the version, tag it in git, regenerate the changelog from your git commits and push the whole thing to rubygems and your remote.

If you prefer you can do it in two steps (which gives you a chance to edit the generated changelog)

rake version:(tiny|minor|major):bump

At this point, edit your changelog to reflect whatever comments or formatting you’d like. When you’re done, run the following

rake version:push

Common Workflow

Here is an example of a common usage for Tumbler. Let’s say I want to create a new gem. Let’s walk through the process:

$ tumbler your_gem_name
$ cd your_gem_name

This will generate the basic gem structure. Now we need to configure the ‘your_gem_name.gemspec’ with gem details and configure ‘Gemfile’ with the external dependencies. That’s all you need to get started! From here, simply implement your gem. When ready for your first release you should first test locally:

# test your gem locally
$ rake gem:install

When you feel confident and you are ready to push your first version to git and rubygems, simply invoke:

# releases your gem
$ rake version:tiny:release

and that does it! Your gem is now released onto the world.

What’s next?

I’m sure there are bugs and other common workflows that I will add and/or document, but basically, I just wanna type a lot less when I bump a gem, and get more things done.

How is this different from Jeweler?

Clearly worth explaining briefly how this gem differs from Jeweler to help people to understand why they might want to use this instead. Will flesh this section out very soon. Dynamic gemspec, better version practice, closer integration to git, et. al