Search code examples
rubythor

How to make Thor find templates for system installed .thor files?


I've created a .thor script for setting up a new ruby project just the way I like it. I'm using the Thor::Actions directory command to build the app entirely from a template directory structure, as opposed to defining them inline with heredocs. The script directory looks something like this:

rubynu.thor
template/
  bin/
  lib/
    %app_name%.rb.tt
    %app_name%
  README.markdown
  .gitignore
  ...

This works really great, and lets me easily visualize and change individual parts of the template as my taste changes.

But I can't figure out a nice way to get thor to find the template directory once the .thor file is system installed using thor install rubynu.thor. Install sticks a copy of the .thor file into ~/.thor but ignores the template/ directory, and so the templates aren't found anymore.

I don't want to hardcode the source_root path or manually copy over the template directory to ~/.thor. Is there something built-in to thor that handles installing templates along with the .thor file? It would be great if they could be packaged together when installed.

If not, what is the nicest way to get around this? Surely there are system installed thor tasks somewhere that use template files. How'd you do it? I suppose I could bypass thor install and provide this as a gem (though that seems like overkill), or bite the bullet and stick all the template definitions inline in a giant .thor file (less pleasant to make changes to the structure later).

For reference, here is the simple .thor file I'm using:

class Rubynu < Thor::Group
  include Thor::Actions

  argument :app_name

  def self.source_root
    File.dirname(__FILE__)
  end

  def apply_directory_template
    directory 'template', app_name
  end
end

Thanks!


Solution

  • If you set up your .thor file like this:

    <my_thor_commands>/
      templates/
        bin/
        lib/
        ...
       main.thor
    

    thor install <my_thor_command> will look for a file called main.thor, and then install it and anything else in <my_thor_command>. After that, you can rely on:

    def self.source_root
      File.dirname(__FILE__)
    end
    

    which will give you the path to the <my_thor_command> as it was installed.