Ship generators with your ruby gems

February 3, 2012 § Leave a comment

Say I’m building a gem and I want it to do three things.  1) create a new route in the gem user’s routes.rb file  2) add some code that will be executed every time they start their app, and  3) place a controller in their rails controller directory.  How would I allow the gem user to do this with one command?

Let’s see by building a throwaway gem for a rails 3.0+ app.  This post assumes that you understand the basics of building a gem.

In the terminal run:

mkdir my_gem && cd my_gem
mkdir lib && cd lib
mkdir generators && cd generators
mkdir templates && mkdir install && cd templates
touch my_gem.rb && touch my_gem_actions_controller.rb
cd ../install
touch install_generator.rb

Here, when Rails sees the ‘generators’ directory, the generator we are going to create becomes available to rails generate command. The templates directory will store all the files and text we want to add to the user’s app. Now open install_generator.rb and add the following:

module My_Gem
  class InstallGenerator < Rails::Generators::Base
  source_root File.expand_path("../templates", __FILE__)
  def add_my_gem_routes
  route "match '/my_gem', :to => 'my_gem_actions#some_method_in_my_controller'"
  end

  def add_initializer
    template "my_gem.rb", "config/initializers/my_gem.rb"
  end

  def add_controller
    template "my_gem_actions_controller.rb", "app/controllers/my_gem_actions_controller.rb"
  end
 end
end

For the three methods above to work, you need to specify ‘thor’ as a dependency in your my_gem.gemspec file. There, you will also need to specify your ‘lib’ directory as an executable. For an example of a gemspec file go here.

These three methods will be executed when your user runs the generator.

I use the ‘template’ method instead of the better-sounding ‘copy_file’ method so that we can place all our files into a ‘templates’ directory. The ‘template’ function adds this directory to the generator’s PATH. The ‘template’ method also executes any ERB tags found in your template files, and, while this can be powerful, we need to escape them if we’re placing ‘html.erb’ files into the user’s ‘view’ directory lest Rails throws a nomethod error when trying to execute them – we do this by using a double percent (%%) like in this example:


<!DOCTYPE html></pre>
<html>

<head>

<title>my app</title>

<%%= stylesheet_link_tag "<%= file_name %>" %>

<%%= javascript_include_tag :defaults %>

<%%= csrf_meta_tag %>

</head>
<pre>

To review, in the templates directory, we’ve made the files we want to copy into our gem user’s rails app. In the install directory we’ve made the actual generator itself. And in the root of our gem we’ve ensured that our gemspec file lists ‘thor’ as a dependency and the ‘lib’ directory as an executable.

We’re ready to create the gem.

cd /my_gem
gem build my_gem.gemspec
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

What’s this?

You are currently reading Ship generators with your ruby gems at seminal.

meta

%d bloggers like this: