In the time I’ve spent learning to code, I often see a little uptick in difficulty around packages (or dll’s, or gems, or imports, or whatever). Getting to “hello world” is pretty easy, but then getting to a program that prints hello world but also imports some system library for regexes or whatever is slightly harder, and often not covered well in tutorials. So I think that part of basic competency in a language is being able to publish and consume bundled code. I’ve been learning Ruby recently, so I’m going to do three things in this post and the following post:
- Go through making a gem for myself to use in a silly web app.
- Import said gem and use it.
- Import some published gem and use that.
I thought about adding “4. Publish my own gem” but I think public package repositories of all sorts already have an appallingly poor signal to noise ratio, and I don’t want to contribute any more noise. If I end up making a useful gem, I’ll publish that.
So, step 1: Make a gem. It turns out that if you google “make a gem” the first thing that comes back is about Ruby. You don’t get arts and crafts or jewelry until maybe the 3rd or 4th search result.
As is my usual procedure with tutorials, I’ll be following along, and recording any differences or difficulty I might have. I’ll be following the guide on rubygems.org to make this gem.
Instead of a gem that prints hello world, this gem will generate a pronouncible, if silly, made up name. Then, when people go to some page on my web app and refresh, they can see a complaint about a different name every time!
Here’s my folder structure:
$ tree . ├── lib │ └── random_namer.rb └── random_namer.gemspec
class RandomNamer def initialize @vowels = ["a", "e","i","o","u","y"] #it's ok y, I love you. @letters = [*('a'..'z')] @consonants = @letters.select do |letter| !@vowels.include? letter end end def make_syllable @consonants.sample + @vowels.sample end def make_name len = 2 + rand(3) name = "" len.times do name = name + make_syllable end name.slice(0,1).capitalize + name.slice(1..-1) end end
This gem will make a string of 2 to 5 pronouncible syllables whenever
make_name is called.
So how do we make a gem? Well, first we make a .gemspec file, then we call
gem build /path/to/my_gem.gemspec. The example on the tutorial linked above is fine, so I won’t copy it. I will add that you need two-digit months (
2017-1-15) or it will complain, but that’s literally the only problem I had.
After the gem is build, I need to go to my web app’s
Gemfile file and add the following line:
gem 'random_namer', :path=> "/vagrant/my_gems/random_namer"
There are other ways of doing this, but it seemed simple enough. Two things of note about this: (1) the path is the folder that contains my .gemspec file, not the path to the .gempsec file itself, and (2) the folder at
/vagrant is the folder that syncs between my hard drive and the hard drive of the VMs that I spin up through vagrant. Also, (1) implies that each gem that you include with this syntax needs to be in its own folder.
In the controller that I care about, I added three things:
namer = RandomNamer.new, and
@my_name = namer.make_name. (It looked a little weird to me at first that Ruby can sometimes call methods without parentheses, but I’ll get over it.)
In the view, I just added:
<%= @my_name %> and that was it. Every time the page is refreshed there’s a different name there.
Also, the two vagrant VMs from last time worked fine. I was able to
vagrant up dev --provision --provider=virtualbox and test locally. It worked, so then I did
vagrant up aws --provision --provider=aws and it worked on AWS.
The next objective of this post is package managing, which, as far as I can tell, is dead simple in Ruby. Basically, there’s a file in the root of your rails file called
Gemfile, which is a manifest of which packages you need, and where to find them. They can come from an online repository declared at the top of the file, usually
source 'https://rubygems.org', they can be from GitHub, which looks like this:
gem "rails", :github => "rails/rails", or they can be sourced on any git repo that you can reach, like this:
gem "rails", :git => "git://github.com/rails/rails.git", or they can be sourced from the file system, like this:
gem 'random_namer', :path=> "/vagrant/my_gems/random_namer". Bundler, the package manager that uses this file, has a great intro doc and great in-depth docs. Because the existing documentation is so good, I won’t dedicate an entire post to package management, as I had planned to.
I have one or two books that am eager to recommend before I resume the rails tutorial, so I’ll see you next time with a post on what I’ve been reading.
Till then, happy learning!