Gems are Ruby’s way of packaging applications or libraries so they can be easily shared. https://rubygems.org/ is a place where people host their gems to make them publicly available.

Installing a gem from https://rubygems.org/ is very easy:

1
gem install awesome_print

Once you install the gem, you might want to know where it was installed. You can find some information about your gem install by using gem env:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 2.0.14.1
  - RUBY VERSION: 2.0.0 (2015-12-16 patchlevel 648) [universal.x86_64-darwin15]
  - INSTALLATION DIRECTORY: /Library/Ruby/Gems/2.0.0
  - RUBY EXECUTABLE: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - universal-darwin-15
  - GEM PATHS:
     - /Library/Ruby/Gems/2.0.0
     - /Users/adrian/.gem/ruby/2.0.0
     - /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/gems/2.0.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/

The part we care the most about at this time is GEM PATHS. I can see where awesome_print was installed:

1
2
3
$ ls -l /Library/Ruby/Gems/2.0.0/gems/
total 0
drwxr-xr-x  13 root  wheel   442B Oct  3 09:32 awesome_print-1.7.0/

Another interesting thing is what happens when you require a awesome_print. It can be seen using irb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
irb(main):003:0> puts $LOAD_PATH
/Library/Ruby/Site/2.0.0
/Library/Ruby/Site/2.0.0/x86_64-darwin15
/Library/Ruby/Site/2.0.0/universal-darwin15
...
=> nil


irb(main):004:0> require 'awesome_print'
=> true


irb(main):005:0> puts $LOAD_PATH
/Library/Ruby/Gems/2.0.0/gems/awesome_print-1.7.0/lib
/Library/Ruby/Site/2.0.0
/Library/Ruby/Site/2.0.0/x86_64-darwin15
/Library/Ruby/Site/2.0.0/universal-darwin15
...
=> nil

You can see that after requiring awesome_print a new path was added to $LOAD_PATH: /Library/Ruby/Gems/2.0.0/gems/awesome_print-1.7.0/lib.

Creating a gem

We’ve learned how to use a gem. Now, lets learn how to create one of our own. The basic structure of a gem is the following:

1
2
3
4
/some-folder
|--my_awesome_gem.gemspec
|--/lib
   |--my_awesome_gem.rb

If the name of your gem has multiple words, use underscore(_) to separate words, the dash(-) is reserved for separating directories. lib/my_awesome_gem.rb is the entry point for the gem. You can include whatever code you want there. My gem will just extend the Integer class:

1
2
3
4
5
class Integer
  def say_awesome
    puts 'Awesome'
  end
end

For the gem to be valid we also need to fill my_awesome_gem.gemspec:

1
2
3
4
5
6
7
8
9
10
11
Gem::Specification.new do |s|
  s.name        = 'my_awesome_gem'
  s.version     = '0.0.0'
  s.summary     = 'Say awesome'
  s.description = 'Extend Integer so it can say awesome'
  s.authors     = ['Adrian Ancona']
  s.email       = 'adrian@ncona.com'
  s.files       = ['lib/my_awesome_gem.rb']
  s.homepage    = 'http://i.dont.have.one'
  s.license     = 'MIT'
end

Most of the fields are straight forward, but there is one that is very important to get right. s.files needs to contain all the files that are being used by your gem or it won’t work. This step is very error prone, so the best you can do is automate it. Since the gemspec file uses ruby, you can write some code that gets all ruby files and adds them to s.files.

One we have our code and gemspec ready, we can build the gem:

1
gem build my_awesome_gem.gemspec

You should get a message saying that the gem was build successfully. You will also get a file my_awesome_gem-0.0.0.gem. Now, we can install the gem to make it available anywhere in our system:

1
gem install my_awesome_gem-0.0.0.gem

Now, we can test our gem:

1
2
3
4
5
6
[anovelo@localhost awesome-gem]$ irb
irb(main):001:0> require 'my_awesome_gem'
=> true
irb(main):002:0> 1.say_awesome
Awesome
=> nil

This is a very basic gem, but your gem can get as complicated as you want. With this information you should be able to package and share it with the whole world.

[ programming  ruby  ]
Load testing a Rails app with Vegeta
Ruby Bundler