I love gems.
At first I felt uneasy about using gems: like I was letting other programmers do my work for me. But when we can install gems in our software rather than code every feature from scratch, we can more fully-featured, better-tested software more quickly. Also, because the community works collaboratively to solve problems rather than individually to solve the same problem millions of times, the collective solution ends up being more robust and more clever than anyone’s individual solution.
After I became accustomed to using gems, I pictured myself one day extracting some of my own code into gems for others to use.
But I had never done that before—until recently. And it was time to give it a try.
For the non-ruby coders: gem is a word rubyists use to describe a library. The ruby community has lots of them. In a highly unscientific study, I compared the number of open source libraries (from library directories) and the number of programmers (from LinkedIn, glassdoor, and IRS estimates) and found ruby to have more open source libraries per programmer than any other object oriented language. The open source community is a particular strength of ruby from which other language communities could learn.
My first gem is, predictably, a very simple gem. It is called gemfinder. It lives on rubygems.org, the online hub for the vast, vast majority of ruby gems. Here’s its little page:
*sniff* It’s so . . . beautiful!
This gem does two things.
1. If you have gemfinder installed and you type $gemfind rails into your terminal, you will receive the name, URI, description, and version number of the rails gem. You can type in “gemfind [name of any gem you want].” If you type in a name and there is no gem by that name, you will receive a message in the terminal to that effect. This is helpful for either learning more about a specific gem or, if you’re a gem-making enthusiast, checking to see if someone has already taken your brilliant idea for a gem name.
2. If you have gemfinder installed and you type $gem_explore rails in your terminal, you will receive the above four pieces of information about every gem whose name contains “rails.” This is helpful if you want to find other gems to extend or support a gem you already want to use. try it with $gem_explore devise or $gem_explore cucumber to see what I mean.
The most fascinating and foreign concept that I learned in the gem-writing process was that I could get a file to run without having to type $ruby filename.rb. But we’ll get there in time, because first I owe the architects of the gem-making process some serious kudos for how easy it was to get started:
1. Obtain account at rubygems.org
2. $gem push
3. Log in through the terminal
4. $bundle gem gemfinder
Presto: I had a framework for my gem. Also, I was shocked that the gem name I wanted hadn’t already been taken. Later I tried to get started on a gem called “magic,” but that name is taken.
Here is (almost) the entirety of the files in my gem. I have group-selected the ones that I’ll go over here. The selection includes all of the files that I edited, plus also the LICENSE file just for good measure:
*The reason I say “almost” is because I have not opened the ‘pkg’ folder, as you can see above. The pkg folder contains the bytecode for each and every version of your gem ever created. Each file in there is a phalanx of 1s and 0s, and each is also automatically generated when you deploy your new gem version. I did not look inside that folder to make this gem.
Let’s begin at the beginning: the README file.
The README.md file is written in a markup language called Markdown. It’s sort of like HTML in that specific tags tell the page to render specific types of text. The tags, in a lot of cases, are various numbers of pound signs: hence the pound signs before Installation and Usage. That said, I didn’t add that. That was all already in the file. The only thing I did in this file was update the “Usage” body text to tell people how to use the gem.
For this gem, I tried out a development workflow called readme-driven-development. Like test-driven-development, I would first describe what I wanted the gem to do, then I would implement that. The difference was that I would describe the gem’s behavior in the instructions issued to the user, rather than with tests in a test file.
Next, the gemfinder.gemspec file:
Once again, I only edited a few spots on the gemspec file. I edited the summary and the description, again to describe the gem’s behavior to humans. I made one other change to this file from its out-of-the-box format: I added the final line spec.add_dependency “gems” to tell the gem that it would need to load another gem to run. That gem, called gems, is a wrapper for the rubygems.org API, which allows someone like me or you to write ruby code that can access the gem information database. As an aside, if you’re looking for a well-written wrapper, the gems gem is an exemplary specimen in the writing and documentation of wrappers.
OK, quickly, the license file:
Gems come standard with the MIT License. It’s a common license to use in the open source community, but it is also an excellent document for you to find out how you can expect your gem to be used by other programmers. In a Western society where “it’s all about me” has somehow become a dominant, expected, and even applauded attitude, the idea of open source can befuddle people. Frankly, that’s a massive cultural loss; it’s also a personal loss that contributes a great deal to the absurdly high prevalence of anxiety and depression in the West. Perhaps in the future, a forward-thinking teacher will include the MIT license among other readings in a unit designed specifically to un-teach the use of competitiveness as a panacea in Western schools. But nobody asked my opinion, so we’ll move on.
OK, onward to gemfinder.rb:
This is the whole file. It defines gem requirements and designates the module.
What is a module?
A module is a category that you wrap around the classes in your code to designate which apps and folders those classes belong to, so you are not barred from using the same class names for other things. Say you were making a web application for Insomnia Cookies. You might want a class called cookie to describe the pastries in the app, but you might also want a class called cookie to describe the cookies you use to track user information. By wrapping the first class in a module called pastry and the second in a module called server, you could avoid having to purposely come up with non-obvious names for things.
In a gem in particular, it is the responsible and considerate thing to do to wrap all classes inside of modules. After all, if thousands of people might download your gem for use, there’s a chance that one of those people will have a class somewhere with a name identical to that of one of your classes. Modules ensure that your software doesn’t break their software, which wouldn’t be a very positive contribution to make.
The version file:
Each time you release an updated version of your gem to the world, you’ll need to update the version. This allows you and others to keep track of which iteration of the software they are using. What you’re seeing here is semantic versioning—a notation that helps other programmers understand the changes you made—and it’s used in all kinds of software. It has three numbers, each separated by periods. The one on the far right is for quick bug fixes, security patches, and similar little repairs. The middle number is for minor changes to the functionality of the app or gem. The number on the far left is for major changes to the functionality of the app or gem. How do you decide if it’s minor or major? Well, it’s subjective, but a good rule of thumb is this:
If the changes you made are big enough that updating the gem could break an application, then it’s a major change.
Very high-traffic gems, like Rails, are very, very careful about this, and for good reason: if they make a change, they run the risk of breaking thousands of apps. As a result:
- Rails has major version changes only every few years, postponing hundreds of useful but software-behavior-changing commits until such time as they are ready to version up in a big way
- Every tiny change undergoes massive debate (more on this later)
- Even after a major update, the Rails core team continues to make small updates to older versions for the benefit of thousands of programmers still using the old version. Right now, for example, they update Rails 4.0 and 4.1.
When you re-release your gem, rubygems.org prevents you from pushing it to the community until the version has been updated. Now you know why.
Onward! The finder.rb file:
Though this file still isn’t huge, it was by far the one to which I added the most lines of code in my whole gem. That’s because I put the methods here that my gem uses to run.
If you’re familiar with ruby, then you’re looking at this file and looking for the catch. There’s no catch. Yep, that’s just ruby. I require the gem at the top that will allow me to access the rubygems API. Then, in the ensuing code, I have my module, my class, and my two methods that call the API, parse the hashes of data it spits back, and arranges it in a format more pleasing to human eyeballs.
Now then: executables. This is the type of file that can be run without ruby and .rb on it. It looks so clean and exciting in the terminal, but there’s less exciting code behind the scenes to set it up. I suppose this is the way with things; more on that in another post. The two executables I have are called gemfind and gem_explore because those are the two methods I want people to be able to run without extra mumbo jumbo on them. I made a folder called /bin in my gemfinder folder, and then I named two files inside after the two methods I wanted called:
This is the behind-the-scenes code of the executables. That first line looks like a comment, but in this (rare) case, it is needed there to inform that program what to do with these files: run them as ruby in the production environment.
The next line tells the file to require that plain ruby file in which we put those two methods.
The next line defines search_terms as the very first item in the array of things that gets returned after the name of the method we want to call. In this case, it’s the parameter we pass in.
And finally, finally, we create a new instance of our Finder class where we put our methods, and we call the requisite method inside that class just like we would do for any ruby program.
As you can see, I’m not in my gemfind directory—I’m in the directory for a different app. Once a gem is installed in your system, you can run it from anywhere.
A search for cucumber reveals a bevy of gems designed to make use of the cucumber gem easier and more widely applicable. Not all results shown.
When the time came to deploy my finished gem to the world, I found the terminal commands just as few as when I created it:
1. Initialize git with $git add . and $git commit -m “message”
2. Put it up on GitHub
3. $rake release
Yes, really. That’s it. And the kickback text?
Four lines in a delightful shade of green.