Creating a Ruby Gem for Total N00bs

The other day I announced that this site would be powered 100% by Ruby and my first project (besides this Octopress powered blog) is a Ruby Gem to upload files to S3 and do other cool stuff with your S3 account. Well, as a beginner to Ruby, creating a gem is quite daunting. There are a ton of tools and tutorials out there that do a great job of teaching you how to create a gem but all of them seem to assume you know the most basic things about Gems. One thing that can easily trip you up in creating your gem is the creation of an executable. Bundler does something very tricky and after seeing what it does I now know why Rubygem pros always say to write your gemspec from scratch,

The Gemspec file for my latest (in development) gem looks like this:

Sploder’s .gemspec file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib', __FILE__)
#bin = File.expand_path('../bin', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'sploder/version'

Gem::Specification.new do |gem|
  gem.name          = "sploder"
  gem.version       = Sploder::VERSION
  gem.authors       = ["Bill Patrianakos"]
  gem.email         = ["bill@billpatrianakos.me"]
  gem.description   = 'Sploder is the S3 uploader'
  gem.summary       = 'Easily upload files to S3, create buckets, set ACL, and more'
  gem.homepage      = ""

  gem.add_dependency "thor"
  gem.add_dependency "aws-sdk"
  gem.files         = `git ls-files`.split($/)
  gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
  gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
  gem.require_paths = ["lib"]
end

Pretty straightforward, right? I removed some of the dynamic stuff and it looks a lot like it was written by hand. But notice this line:

Sploder’s .gemspec file
1
gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }

This line dynamically pulls in your binaries from your /bin folder. It worked fine when I created the gem on the original computer I wrote it on but when I pushed it up to my private repo and pulled it back down again it wouldn’t run when I called the executable! Why? I updated my gems, created a new gemset, updated my Ruby version, and on and on but I still couldn’t get my executable to run. Bundler’s gemspec was the reason.

Don’t ask me why but for some reason it wasn’t pulling in the binaries from the right place so rather than relying on Bundler’s executable line to discover my gem’s executables I did it the old fashioned way and replaced the line above with this line:

Adding a gem executable
1
gem.executables << 'sploder'

After replacing the original with this my gem sprung to life.

So do what the masters say and write your gemspec from scratch!

Programming, Ruby

« Say Fuck You to Someone Today Introducing Sploder, the S3 Uploader »

Comments