Huzzah! I finally wrestled my Recall code into a legit Ruby Gem!
Here’s the updated GitHub repo and here’s the super-official RubyGem page. You can install it by simple running gem install recall
from your command line!
Big thanks to Flatiron alum Kevin Curtin for his help organizing and connecting the various files.
Here’s a quick summary of the rather arduous process I went through to get the working script into a gem. This outline may not be exactly correct, as it took me a little over a week to finally whip my directory structure and require_relative
s into proper order, but it is roughly how this went down.
1. Bundler’s Skeleton
I ended up using Bundler’s built-in gem skeleton generator. I ran bundle gem recall
in a fresh, empty directory and got a scaffolded-out directory for the gem. But I still had some big hurdles to get over.
2. Gemspec File
Next, an easy bit. I filled out the gemspec file that Bundler gave us with our personal information.
3. The Transfer
I then transferred code (models, a runner, and a template) into the appropriate folders inside the skeleton of directories that Bundler created for me. This involved a lot of guess-and-gem-build.
Models and template: I put both of my model files and the templates folder (containing the one template) into lib/recall/
.
Runner: My “runner” went into bin/
and I renamed it recall
with no extension.
That weird recall.rb file: Bundler created a module called Recall
in lib/recall.rb
for me. I guess I’ve come to think of this file as the bridge between my runner (bin/recall
) and my lib/recall/
directory, which has all my models and templates.
Why a module? The reason for making it a module is to protect it from naming conflicts. For example, Recall has a model called Results. We wouldn’t want anyone using my gem to have a conflict when they call their Results class. So now my Results model effectively becomes Recall::Results (the :: is the scope operator).
Connecting the “bridge” file to my models and templates: The lib/recall.rb
(again, the “bridge” file) has a require_relative
pointing to each model– Results and SiteGenerator– after the module definition. Here’s the entire file in all its weirdness:
require "recall/version"
require 'erb'
module Recall
end
require_relative 'recall/results.rb'
require_relative 'recall/site_generator.rb'
The SiteGenerator model calls the template with the expand_path
method, so we didn’t need to require_relative
it here.
Connecting the runner to the “bridge” file (scope operators all over): In bin/recall
, the models Results and SiteGenerator are called as Recall::Results
and Recall::SiteGenerator
, respectively, to associate them with the Recall
module declared in lib/recall.rb
. Oddly, we also found that we had to change their declarations to include the Recall module and the scope operator.
A Hiccup When Connecting One of the Models to the Template and the Output File
In addition to the problem of my bin/recall
runner not being able to find my Recall module until we put scope operators all over the place, it was also difficult to connect my SiteGenerator
model to the files it needed to access. SiteGenerator
needs access to both the .rb.erb template, located in lib/recall/templates
, to know how to render the search results, as well as the temporary file where it dumps the search results. Kevin recommended I try File’s expand_path method for these connections and that did the trick. Here’s how we connected to the template:
template_file = File.expand_path("../templates/sublime.rb.erb", __FILE__)
And here’s how we connected the SiteGenerator model to the output file it writes to:
output_file = File.expand_path("../_site/ruby_file.rb", __FILE__)
(I’m still not 100% why this was necessary.)
As a recap, here is the current directory structure:
4. Building the Gem (over and over again)
Now that we’ve got the directory structure and file connections just right, it’s time to build our gem locally and see if it works! (OK so in actuality I attempted and failed to build this gem correctly numerous times. Each time I made a change to the code, I’d have to re-build it and re-install it to see what affect the change had on how the gem performed.)
To build the gem locally, you run the following command:
gem build recall.gemspec
This creates a new .gem file (with the version number appended) in your gem’s root directory. You then can run gem install recall
to install the gem locally and then you can try it out. Whenever I needed to make another change, I’d gracefully rm
the .gem
file, re-build and re-install the gem locally, and try again. Thankfully, you are able to keep the same version number throughout this process so the number of times I had to do this will be forever unknown to others.
5. Publishing the Gem to RubyGems.org
Once I successfully built the gem locally, and liked how it functioned, publishing the thing was surprisingly easy. As per the RubyGems’ publishing guide, I simply created an account at RubyGems.org then and ran gem push recall-0.0.2.gem
in my local directory. To test it, I first uninstalled my local copy of version 0.0.2, then ran gem install recall
and lo and behold it seems to work!
Also!
In preparation for its public debut, I added a good amount of flow control to the runner to allow users to set and change the search directory as they please. Their search directory choice is stored in a .txt file called search_map, which I put in lib/recall
. If that file is empty or for some reason doesn’t exist, users are prompted to enter the absolute path of their desired search directory when they first call the gem. After that it’s set, although users can edit the search directory by “searching” for change_dir
.
I think that about covers it. Give it a try? You can always uninstall it!
For more info be sure to visit the GitHub repo. As usual, there’s plenty of improvements to be pull-requested and merged.