How to compose Thor tasks in separate classes/modules/files?

Nick Klauer picture Nick Klauer · Apr 20, 2011 · Viewed 7.9k times · Source

I'm having some trouble getting Thor to do this, so hopefully someone can point out what I'm doing wrong.

I have a main class class MyApp < Thor that I want to break out into separate files for multiple namespaces, like thor create:app_type and thor update:app_type. I can't find any examples that show how one should break apart a Thor app into pieces, and what I've tried doesn't seem to work.

Take for instance, this class I'm trying to break out from the main Thor class:

module Things
  module Grouping

    desc "something", "Do something cool in this group"
    def something
      ....
    end
  end
end

When I try to include or require this in my main class:

class App < Thor
  ....
  require 'grouping_file'
  include Things::Grouping
  ....
end

I get an exception: '<module:Grouping>': undefined method 'desc' for Things::Grouping:Module (NoMethodError)

Is it possible to have multiple namespaces for Thor tasks, and if so, how does one break it out so that you don't have one monolithic class that takes several hundred lines?

Answer

semperos picture semperos · Sep 30, 2011

Use an over-arching module, let's say Foo, inside of which you will define all sub-modules and sub-classes.

Start the definition of this module in a single foo.thor file, which is in the directory from which you will run all Thor tasks. At the top of the Foo module in this foo.thor, define this method:

# Load all our thor files
module Foo
  def self.load_thorfiles(dir)
    Dir.chdir(dir) do
      thor_files = Dir.glob('**/*.thor').delete_if { |x| not File.file?(x) }
      thor_files.each do |f|
        Thor::Util.load_thorfile(f)
      end
    end
  end
end

Then at the bottom of your main foo.thor file, add:

Foo.load_thorfiles('directory_a')
Foo.load_thorfiles('directory_b')

That will recursively include all the *.thor files in those directories. Nest modules within your main Foo module to namespace your tasks. Doesn't matter where the files live or what they're called at that point, as long as you include all your Thor-related directories via the method described above.