How I Start My Gems
02 Jul 2014Resources
Introduction
I’ve built quite a few rubygems and I’d like to share how I begin my gems nowadays.
For the purposes of this article, assume that we want to build a gem called bad_math
.
This article will not cover how to build a gem, merely how to make it easier on the developer.
If you’ve not built a gem before, I recommend watching Railscast #245: New Gem with Bundler.
Prerequisites
bundler
Generate Gem Template
Yes, I could build the gem directory/file structure manually, but that’s too slow, and bundler makes it hella easy. (I do recommend doing it manually at least once to appreciate what bundler does for you.)
Running bundle gem bad_math
will output something similar to the following:
[~/workspace/gems] $ bundle gem bad_math
create bad_math/Gemfile
create bad_math/Rakefile
create bad_math/LICENSE.txt
create bad_math/README.md
create bad_math/.gitignore
create bad_math/bad_math.gemspec
create bad_math/lib/bad_math.rb
create bad_math/lib/bad_math/version.rb
Initializing git repo in ~/workspace/gems/bad_math
Look at that! I’ve got a template and all I have to do is fill in the blanks and start coding.
Modifying the gemspec
For additional reading, you can view the gem specification reference to see all of the various
configuration options that are available to you within this file. For the sake of this article, I’m only concerned with adding
yard
and redcarpet
to my development dependencies.
spec.add_development_dependency "yard"
spec.add_development_dependency "redcarpet"
These gems work together to provide a very straightforward way of documenting my gem as I build it. I’ve found that if I have the capability to document from the get go, I’m more likely to actually write documentation, because nobody likes an undocumented gem.
Rakefile Addition
1 task :console do
2 require 'irb'
3 require 'irb/completion'
4 require 'bad_math'
5 ARGV.clear
6 IRB.start
7 end
After reading the short “7 Lines Every Gem’s Rakefile Should Have”, I’ve been adding this to my gems ever since. As Ernie states, nothing beats playing around in the console, and no you don’t need to use IRB. You can use the console of your choice. The point is to start it up a console and load your gem so you can play around with it.
Configurable From the Start
I’ve written gems that started off with what I thought would be rock solid functionality, but find out later down the road that it’s more flexible than I’d originally thought. This is the reason why the first functionality I add is a Configuration class. With configuration set up from the start, it’s easier to stay flexible with functionality. Believe me, it’s a pain in the ass to add configuration functionality after the fact that your logic has mostly been written.
lib/bad_math/configuration.rb
1 module BadMath
2 class Configuration
3 # These are our configuration options.
4 attr_accessor :nonesuch
5
6 def initialize
7 # default the values here
8 @nonesuch = nil
9 end
10 end
11 end
lib/bad_math.rb
1 require "bad_math/version"
2 require "bad_math/configuration"
3
4 module BadMath
5 # Customize configuration for library
6 # @yieldparam [Configuration] config
7 def self.configure
8 yield self.config if block_given?
9 end
10
11 # @return [Configuration]
12 def self.config
13 @@config ||= Configuration.new
14 end
15 end
So now if I need to use a configurable ‘foobar’ option, I will:
- Add the option to the Configuration class (if not already) (
attr_accessor :foobar
)- I use attr_accessor because I want to be able to modify the value at any point.
- If I need to keep a value from changing, I’ll use attr_reader instead.
- Set a default value (Configuration#initialize:
@foobar = ""
) - Use it by calling
BadMath.config.foobar
- PROFIT!!!
User Configuration
1 BadMath.configure do |cfg|
2 cfg.nonesuch = "I'm not here"
3 cfg.foobar = "bizbang"
4 end
Summary
Boom! Bundler to flesh out the boring templating, yard/redcarpet for simple documentation, and a simple configuration setup.
Happy Coding!